C++ 为什么删除的移动语义会导致std::vector出现问题?

C++ 为什么删除的移动语义会导致std::vector出现问题?,c++,c++11,C++,C++11,在做了一些研究之后,我发现分配器要求类型是可移动/可复制的。我确信这就是问题的原因,但是我对删除和未声明的移动语义之间的行为感到困惑 我有以下代码无法在MSVC12和Clang上编译: #include <vector> class Copyable { public: Copyable() = default; Copyable(Copyable const& other) : m_int(other.m_int) {} Copya

在做了一些研究之后,我发现分配器要求类型是可移动/可复制的。我确信这就是问题的原因,但是我对删除和未声明的移动语义之间的行为感到困惑

我有以下代码无法在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{});
}
#包括
类可复制
{
公众:
Copyable()=默认值;
可复制(可复制常量和其他)
:m_int(其他.m_int)
{}
可复制和运算符=(可复制常量和其他)
{
m_int=其他m_int;
归还*这个;
}
可复制(可复制&&)=删除;
可复制&运算符=(可复制&&)=删除;
私人:
int m_int=100;
};
int main()
{
向量对象;
对象。向后推(可复制{});
}
无法在MSVC上编译,原因是:

xmemory0(600):错误C2280:'Copyable::Copyable(Copyable&&'):尝试引用已删除的函数

在叮当声中():

new_分配器。h:120:23:错误:调用“Copyable”的已删除构造函数

在这两种情况下,当我删除显式删除的move-construct/assign方法时,代码将编译。AFAIK当您声明复制分配/构造方法时,编译器不会隐式声明相应的移动成员。所以它们仍然应该被有效地删除,对吗?当我删除move-construct/assign的显式删除时,为什么代码会编译


对于这个C++11缺陷,通常有什么好的解决方法?我不希望我的对象是可移动的(但它们是可复制的)。

删除函数与不声明函数不同

声明一个已删除函数并参与重载解析,但如果试图调用它,则会产生错误

如果未能声明移动构造函数,编译器将不会在创建复制构造函数时创建移动构造函数。右值上的重载解析将找到您的复制构造函数,这可能是您想要的

您对
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)
}
void do_stuff(intx){std::cout
除非你是移动语义学方面的专家(我的意思是,真的知识渊博),否则永远不要删除特殊的移动成员。它不会做你想做的事情。如果你查看了其他人的代码,就把它说出来。解释必须非常可靠,而不是“因为我不希望类型移动”

不要这样做

正确的方法是简单地声明/定义复制成员。移动成员将被隐式禁止(不删除,但实际上不存在)。只需编写C++98/03即可


有关更多详细信息,请参见。

通过副本实现移动?另外,与:+1相关的是,这是一个实用的建议,尽管有很多有用的参考资料,但很难找到。写一本关于所有这些优秀内容(移动语义、参数传递、类设计、日期、排列和线程)的小书怎么样这些年来,您一直在这里整理(并在libc++中使用)?正如@ShafikYaghmour正确指出的那样,这一切都很难找到,而且很分散。@TemplateRex:正在寻找时间。。。
Copyable(Copyable&&) = delete;
Copyable& operator= (Copyable&&) = delete;