c++ - 尝试通过引用将 const 成员传递给类时引用已删除的函数
问题描述
这是对在通过 const 成员通过引用传递时尝试引用已删除函数的问题的一种扩展
我读到了,我确实理解了有关 MoveConstructible 的解释(或者至少,我相信),但鉴于以下代码,我无法弄清楚原因:
struct vertex {
const double x;
const double y;
const double z;
};
const std::vector<vertex> test_vertices()
{
std::vector<vertex> vertices;
vertices.emplace_back(vertex(-3.0, -3.0, 0.0));
vertices.emplace_back(vertex(3.0, -3.0, 0.0));
vertices.emplace_back(vertex(0.0, 0.0, 1.5));
}
这段代码完美无缺:
std::vector<vertex> panel_vertices = test_vertices();
draw(panel_vertices);
但此其他代码没有并返回“C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\xutility(1762,1): error C2280: ' p_geometry::vertex &p_geometry::vertex::operator =(const p_geometry::vertex &)':试图引用已删除的函数”(忽略命名空间,它们在代码中是可以的):
class PanelView {
std::vector<vertex> vertices;
public:
PanelView(int x, int y, int w, int h, const char* l = 0);
void setVertices(const std::vector<vertex>& vertices): vertices(vertices) {};
void draw() {
other_draw(vertices);
};
};
我这里没有排序运算符,但除此之外,我还遗漏了一些东西,因为两个代码片段似乎都在做同样的事情。
更新
在您回复后(谢谢!!)我试图澄清我的想法和怀疑。我尝试了几种配置,并且我可以在有 const 成员时删除复制运算符(恕我直言,这是一个非常愚蠢的行为,因为当您创建副本时,您并没有尝试修改原始文件中的任何内容,但这不在这个问题的范围)。
我得出以下四种情况 [1, 2, 2bis, 3]:
#include <iostream>
struct vertex {
const double x;
const double y;
const double z;
};
const std::vector<vertex> test_vertices()
{
std::vector<vertex> vertices;
vertices.push_back(vertex {-3.0, -3.0, 0.0});
vertices.emplace_back(vertex{3.0, -3.0, 0.0});
vertices.emplace_back(vertex{0.0, 0.0, 1.5});
return vertices;
}
class PanelView {
std::vector<vertex> mvertices;
std::vector<vertex> *mvpointer;
public:
//[1] PanelView(const std::vector<vertex>& vertices): mvertices(vertices) {};
//[2] void setVertices(const std::vector<vertex>& v) {mvertices = v; };
//[2 bis] void setVertices(std::vector<vertex> v) {mvertices = v; };
//[3] void setVerticesPointer(std::vector<vertex> *v) {mvpointer = v; };
void draw() {std::cout<<mvertices[0].x; };
void drawp() {std::cout<<(*mvpointer)[0].x; };
};
int main()
{
std::vector<vertex> panel_vertices = test_vertices();
//[1] Works fine
//PanelView pv(panel_vertices);
//pv.draw();
//[2 and 2 bis] - Error C2280: 'vertex &vertex::operator =(const vertex &)': deleted
//PanelView pv;
//pv.setVertices(panel_vertices);
//[3] - OK
PanelView pv;
pv.setVerticesPointer(&panel_vertices);
pv.drawp();
std::cout<<panel_vertices[0].x;
}
PanelView 构造函数 [1] 和 setVertices 方法 [2 和 2 bis] 执行相同的操作,将“const std::vector& vertices”作为输入并将其(或什么?)复制到类属性“std::vector顶点;"。
第一个疑问:为什么使用 setVertices 方法会失败,而使用构造函数却不会?“幕后”有什么区别?
第二个疑惑:我一直认为在 C++ 中通过引用传递和通过指针传递基本相同,但是通过引用传递更多的是 C++ 风格,并且避免了所有样板代码,使其更具可读性。为什么编译器抱怨 [2 (by reference)],但对 [3 with pointers] 没问题?
解决方案
简单的答案是,在您的示例中 operator= - 被删除 - 没有被调用,这就是它起作用的原因。对比:
setVertices(const std::vector<vertex>& v)
接受一个现有的向量并将每个值一个接一个地复制vertices
到一个新的向量中。好吧,至少这是编译器尝试生成的代码,类似于:
vertices.reserve(v.size);
for (size_t i = 0; i < v.size(); ++i) {
vertices[i] = v[i];
}
请注意,上面的代码期望operator=
分配一个vertices[i] = v[i];
另外,注意:) 这不是 STL 将生成的实际代码 - 它仅用于说明operator=
预期的位置。实际代码最有可能使用通用复制算法和迭代器。
至于您的示例-在调用复制构造函数时vertices.emplace_back(vertex(0.0, 0.0, 1.5));
不需要operator=
请求-我相信它是默认生成的。复制构造函数通过放置 new 调用。
推荐阅读
- angular - Angular Firestore (angularfire2) - 拉取与“照片”ID 匹配的所有“评论”
- typescript - lib.dom.ts 文件中的最新打字稿重大更改
- statistics - 如何仅使用样本量和置信水平计算置信区间
- objective-c - 我正在使用 if 语句来检查键是否为空,但我不明白出了什么问题
- c# - 在选择正确的数据结构时需要帮助
- android - 在原生条码扫描器中添加关闭按钮
- python - Pandas:使用 Append 添加新列并生成另一个全 NaN
- python - 限制两个数字之间的输入并同时检查输入是否为数字
- python - 使用浏览器的对话框(带提示)使 Python 下载文件
- mysql - sequelize error: missing index for constraint