我上的是2017。最近,由于我不喜欢C++的不符合标准,所以我继续在选项中禁用了非标准语言扩展。到目前一切尚好。现在我有麻烦了。
#include <iostream>
#include <vector>
struct Vertex
{
Vertex(float pos) { }
Vertex(Vertex& other) { }
};
std::vector<Vertex> arrayOfVertices;
int main()
{
arrayOfVertices.emplace_back(7.f);
}这不会在Visual中编译,唯一的错误是:
“编译器中发生了内部错误”
如果我启用了语言扩展,它就会编译得很好。如果我禁用语言扩展并使复制构造函数采用const Vertex&,那么它就会编译得很好。
因此,我在一些在线编译器上试用了GCC,如果复制构造函数不使用const引用参数,它就不会编译,从而产生各种错误。似乎最有意义的是:
错误:从‘顶点’类型的r值中初始化“顶点&”类型的非const引用无效
我认为复制构造函数不必是const,在我的例子中,我想修改另一个引用中的一些内容。我知道非const参数不能接受r值引用,但是我对它进行了测试,结果发现在vector::emplace_back()中根本没有调用复制构造函数:
#include <iostream>
#include <vector>
struct Vertex
{
Vertex(float pos)
{
std::cout << "Calling constructor\n";
}
Vertex(const Vertex& other)
{
std::cout << "Calling copy constructor\n";
}
};
std::vector<Vertex> arrayOfVertices;
int main()
{
arrayOfVertices.emplace_back(7.f); // Normal constructor called if const,
// doesn't compile if non-const
auto buff = malloc(sizeof(Vertex)); // Placement new
new (buff) Vertex(7.f); // Normal constructor called whether const
// or non-const. This is what I thought emplace_back did
}所以我不知道怎么回事。首先,我想知道为什么在没有调用复制构造函数的情况下会发生这种情况,以及在本例中是否有一种方法在我的复制构造函数中使用一个非const,即使用vector::emplace_back(),因为这个问题似乎只出现在使用vector::emplace_back()。
发布于 2017-10-14 11:47:15
问题是您没有移动构造函数。
当您请求std::vector到emplace_back时,它必须确保它有足够的存储空间来构造新的对象。这个例程的一部分是实例化一堆代码,如果需要的话,会将元素从旧缓冲区移动到任何新分配的缓冲区。即使在运行时没有重新分配,该代码也将被模板实例化。
您的类有一个用户定义的复制构造函数,因此移动构造函数被隐式删除。因此,试图将原始缓冲区中的任何元素移动到新的,将变成试图复制,通过过载解析。你把注意力放在新的位置上,实际上是一条红鲱鱼,在这个简单的例子中,真正的问题是显而易见的:
Vertex v1{7.f},
v2{std::move(v1)};
// Error, the xvalue from `move` can't bind to a non-const reference例如,通过显式地默认移动构造函数,您可以很容易地使错误保持沉默:
struct Vertex
{
Vertex(float)
{
std::cout << "Calling constructor\n";
}
Vertex(Vertex&&) = default;
Vertex(Vertex&)
{
std::cout << "Calling copy constructor\n";
}
};永远不要忘记,在C++11中,0/3的规则变成了0/3/5的规则。
发布于 2017-10-14 11:44:46
显然,如果编译器给出内部错误,这就是编译器的错误。
emplace_back(7.f)使用构造函数Vertex(float pos)嵌入对象--没有直接涉及复制构造函数。
错误的实际原因是不同的。通常情况下,当您放置在向量中时,可能会发生重新分配。如果是这样的话,那么向量中的所有对象都必须重新定位到内存中的一个新位置。
显然,对于是否发生重新分配,这是一个运行时条件。在运行时出现编译错误是不可行的;因此,如果对象不支持重新分配,那么在编译时使用emplace_back时就必须发生错误;即使这个调用的向量恰好是空的。
标准术语在C++14表87中找到:为了嵌入到向量中,元素类型必须是MoveInsertable和MoveAssignable。
在不涉及太多细节的情况下,非const复制构造函数和没有移动构造函数的组合意味着对象失败了MoveInsertable需求,因为在上述需求中的rvalue参数不会绑定到非const值引用。
https://stackoverflow.com/questions/46743898
复制相似问题