在做了一些研究之后,我发现C++ 11的分配器存在缺陷,需要类型可移动/可复制.我确定这是导致这个问题的原因,但我对删除和未声明的移动语义之间的行为感到困惑.
我有以下代码无法在MSVC12和Clang上编译:
#include <vector>
class Copyable
{
public:
Copyable() = default;
Copyable(Copyable const& other)
: m_int(other.m_int)
{}
Copyable& operator= (Copyable const& other)
{
m_int = other.m_int;
return *this;
}
Copyable(Copyable&&) = delete;
Copyable& operator= (Copyable&&) = delete;
private:
int m_int = 100;
};
int main()
{
std::vector<Copyable> objects;
objects.push_back(Copyable{});
}
Run Code Online (Sandbox Code Playgroud)
这无法在MSVC上编译:
xmemory0(600):错误C2280:'可复制::可复制(可复制&&)':尝试引用已删除的函数
而对于Clang(现场样本):
new_allocator.h:120:23:错误:调用'Copyable'的已删除构造函数
在这两种情况下,当我删除显式删除的移动构造/分配方法时,代码编译.AFAIK在声明复制赋值/构造方法时,编译器不会隐式声明相应的移动成员.所以它们仍应被有效删除,对吧?当我删除move construct/assign的显式删除时,为什么代码会编译?
一般来说,这个C++ 11缺陷有什么好的解决方法?我不希望我的物体可以移动(但它们是可复制的).
Yak*_*ont 14
删除功能与不声明功能不同.
声明已删除的函数并参与重载解析,但如果您尝试调用它,则会产生错误.
如果未能声明移动构造函数,编译器将不会在创建复制构造函数时创建一个.rvalue上的重载分辨率将找到您的复制构造函数,这可能是您想要的.
你跟你说的foo(foo&&)=delete
是"如果有人试图移动构造这个对象,就会产生错误".
我可以在这里说明不同之处:
void do_stuff( int x ) { std::cout << x << "\n"; }
void do_stuff( double ) = delete;
void do_stuff2( int x ) { std::cout << x << "\n"; }
//void do_stuff2( double ) = delete;
int main() {
do_stuff(3); // works
//do_stuff(3.14); // fails to compile
do_stuff2(3); // works
do_stuff2(3.14); // works, calls do_stuff2(int)
}
Run Code Online (Sandbox Code Playgroud)
上述问题的唯一部分使得这一点更加混乱,特殊的成员函数是根据略有神秘的规则自动创建的.
How*_*ant 10
Copyable(Copyable&&) = delete;
Copyable& operator= (Copyable&&) = delete;
Run Code Online (Sandbox Code Playgroud)
除非你是在移动语义方面的专家(我的意思是,真正懂行),永远不会删除特招会员.它不会做你想要的.如果您查看已执行此操作的其他人的代码,请将其调出.解释必须非常扎实,而不是"因为我不希望这种类型移动".
只是不要这样做.
做你想做的事的正确方法是简单地声明/定义你的副本成员.移动成员将被隐式禁止(不删除,但实际上不存在).只需编写C++ 98/03.
有关详细信息,请参阅此答案.
归档时间: |
|
查看次数: |
1095 次 |
最近记录: |