移动语义是不完整的?

use*_*280 10 c++ language-features move-semantics c++11

在复制效率低下的情况下,移动语义替换复制语义.复制语义完全处理可复制对象,包括const对象.

在c ++ 11中已经存在无数的不可复制对象,例如std :: unique_ptr.这些对象完全依赖于移动语义,因为从对象移动允许使其无效.这对于像RAII这样的流行设计模式很重要(imho).

将const不可复制对象分配给内存区域时会出现问题.无法以任何方式恢复这样的对象.

这在对象的生命周期中显然很重要,因为它的常量.在它的生命周期结束时,当调用析构函数时,(不存在的)对象简单地是非常量的.

我建议移动析构函数可以成为移动语义模型的一个有价值的补充.

考虑一个简单的情况,其中unique_ptr用于unordered_set.您可以insert使用移动构造函数(或构造"emplace")进入此集合,但是如果您想将此指针移动到另一个unordered_set(即保持它为const),那么这将是不可能的.

必不可少的,有一个iterator insert((possibly const) key&&)但没有const key&& erase(iterator).事实上,这是不可能的.只能扩展容器以返回指向键的指针,并忘记它.

一个移动的析构函数可以解决这个问题const MyClass&& ~MyClass(),因为它只会在破坏期间违反const(当编译器认为对象无效时).

编辑:我应该指出const MyClass&& ~MyClass() const实际上更有意义.析构函数不必修改anyhting,只会破坏对象,就好像它不再是它控制的任何资源的有效句柄.

How*_*ant 11

Imho你已经确定了一个真正的需求.

你的解决方案听起来很像我所谓的破坏性移动语义.原始移动语义提议中描述了这种可能性.我认为这样的设计是可能的,尽管它并非没有问题.据我所知,没有人在标准委员会这个领域工作.

有一些更简单的方法可以从不需要语言更改的关联容器中提取仅移动类型(除了允许没有未定义行为的类型 - 惩罚).

N3645是一个仅限库的提议,它将嵌套node_ptr类型放入每个容器中.这node_ptr很像一个unique_ptr.它具有关联容器中节点的唯一所有权.但是,当您取消引用它时,您将获得value_type对节点中的非const访问,而不是节点本身. extract并且insert成员被添加到关联容器中,允许用户插入和移除容器的节点(由其拥有node_ptr).

您可以使用它从容器中删除节点,然后将仅移动类型移出节点,并~node_ptr()在完成后清理节点.本文包含此示例以演示此功能:

set<move_only_type> s;
s.emplace(...);
move_only_type mot = move(*s.extract(s.begin())); // extract, move, deallocate node
Run Code Online (Sandbox Code Playgroud)

注意s.extract就是这样noexcept,~node_ptr()当然.如果移动构造move_only_typenoexcept,那么整个操作就是noexcept.否则,如果移动结构抛出,set则保留该项目已被删除set.

目前,N3645尚未取得任何进展.它还没有被投票到工作草案中,我完全没有信心.

更新C++ 17

我的观点是纠正的:我在上面描述的功能是用P0083R3投入C++ 17 .感谢Cosme在下面的评论中提醒我这一点.