C++ 移动会使对象处于可用状态吗?

C++ 移动会使对象处于可用状态吗?,c++,c++11,move-semantics,C++,C++11,Move Semantics,假设我有两个向量,我把一个向量移到另一个向量,v1=std::move(v2);此后,v2是否仍处于可用状态?否,它处于未指定状态 文章节选- 。。move()为其目标提供其参数的值,但没有义务保留其源的值。因此,对于向量,move()可以合理地将其参数保留为零容量向量,以避免复制所有元素。换句话说,移动是一种潜在的破坏性读取 从n3290开始,17.6.5.15从库类型状态[lib.types.movedfrom]移动 < L> C++标准库中定义的类型对象可以从(12.8)移动。可以显式指定

假设我有两个向量,我把一个向量移到另一个向量,
v1=std::move(v2)
;此后,
v2
是否仍处于可用状态?

否,它处于未指定状态

文章节选-

。。move()为其目标提供其参数的值,但没有义务保留其源的值。因此,对于向量,move()可以合理地将其参数保留为零容量向量,以避免复制所有元素。换句话说,移动是一种潜在的破坏性读取


从n3290开始,17.6.5.15从库类型状态[lib.types.movedfrom]移动

< L> C++标准库中定义的类型对象可以从(12.8)移动。可以显式指定或隐式生成移动操作。除非另有规定,否则从物体上移动的物体应处于有效但未指定的状态 由于状态有效,这意味着您可以在
v2
上安全操作(例如,通过分配给它,这将使其返回到已知状态)。但是,由于未指定,这意味着您不能依赖
v2.empty()
的任何特定值,只要它处于此状态(但调用它不会使程序崩溃)

请注意,移动语义的这一公理(“从对象移动的对象处于有效但未指定的状态”)是所有代码都应该努力实现的(大多数时候),而不仅仅是标准库组件。与复制构造函数的语义非常相似,复制构造函数应该进行复制,但不强制执行。

如果要在移动后使用v2,则需要执行以下操作:

v1 = std::move(v2);
v2.clear();
此时,v1将具有v2的原始内容,v2将处于定义良好的空状态。这适用于所有STL容器(以及字符串),如果您正在实现自己的支持移动语义的类,那么您可能需要做类似的事情


如果STL的特定实现确实使对象处于空状态,则第二个clear()实际上是一个不可操作的选项。事实上,如果是这种情况,编译器在移动后消除clear()将是一种合法的优化。

它将处于未指定但有效的状态。也就是说,您仍然可以仅在对象有效的前提下使用对象。例如,您可以对从vector移动的对象调用vector::clear(),使其进入已知状态,然后开始向其中插入对象。它必须有效。否则,当对象超出范围时会发生什么情况。最有可能的是,它的数据存储中没有任何内容,但不管它是什么,它都是有效的。就语言而言,移动后的对象在对象仍然存在的情况下是有效的,可以调用其析构函数而不会导致未定义的行为等。但是,对象的契约可能会因移动而修改。例如,向量已经变为零大小(没有容量)是一个有效的C++向量,但是一个对象,它具有在向量上设置特定元素的方法,而不验证向量现在应该具有特定大小的假设(现在已经失效),……成为不允许的操作(将导致UB)。此类细节应由目标实施者记录。如果需要的话,实现者还应该提供一种文档化的方法来恢复对象的可用性。+1,但从它的编写方式来看,您似乎不知道
v2
v2=std::vector{}之后是否为空这看起来像的副本。看这个答案:这个问题讨论了允许的操作的前提条件。