移动语义是否不完整? [英] Are move semantics incomplete?
问题描述
在复制效率不高的情况下,移动语义会替换复制语义.复制语义完全处理可复制对象,包括const对象.
Move semantics replace copy semantics in situations where copying is inefficient. Copy semantics deals fully with copyable objects, including const objects.
在c ++ 11中已经存在无数不可复制的对象,例如std :: unique_ptr.这些对象完全依赖于移动语义,因为从一个对象移动会使其无效.这对于像RAII这样的流行设计模式来说很重要(imho).
Already, there exists a myriad of non-copyable objects in c++11, for example std::unique_ptr. These objects rely on move semantics completely because moving from an object allows for invalidating it. This is important (imho) for popular design patterns like RAII.
将const不可复制对象分配给内存区域时,会发生问题.这样的对象无法以任何方式恢复.
A problem occurs when a const non-copyable object is assigned to an area of memory. Such an object can't be recovered in any way.
由于对象的恒定性,这在对象的生存期内显然很重要.在生命周期的尽头,然而,当调用析构函数时,(不存在)对象只是短暂的非常量对象.
This is obviously important during the lifetime of the object, because of its constness. At the end of it's lifetime, when the destructor is called however, the (non-existent) object is briefly non-const.
我建议 moving 析构函数可能是对move语义模型的宝贵补充.
I suggest that a moving destructor could be a valuable addition to the move semantics model.
考虑一个简单的情况,在unordered_set中使用unique_ptr.您可以使用move构造函数(或构造"emplace")将insert
放入此集合,但是,如果您想将此指针移动到另一个unordered_set(即保持其const),将是不可能的.
Consider a simple situation where an unique_ptr is used in an unordered_set. You can insert
into this set using a move constructor (or construct "emplace"), however if you wanted to move this pointer to another unordered_set (i.e. keeping it const) it would be impossible.
基本,有一个iterator insert((possibly const) key&&)
但没有const key&& erase(iterator)
.实际上这是不可能的.只能扩展该容器以返回指向该键的一些指针,而不必理会它.
Essential, there is a iterator insert((possibly const) key&&)
but no const key&& erase(iterator)
. In fact it would be impossible. The container could only be extended to return some pointer to the key, and forget about it.
移动的析构函数可以解决此问题,即const MyClass&& ~MyClass()
,因为它只会在销毁过程中(当编译器认为该对象仍然无效时)违反const.
A moving destructor could solve this ie const MyClass&& ~MyClass()
, since it would only violate const during destruction (when the compiler considers the object is invalid anyway).
我应该指出const MyClass&& ~MyClass() const
实际上更有意义.析构函数不必修改任何内容,只需销毁对象,就好像它不再是对其控制的任何资源的有效句柄一样.
I should point outconst MyClass&& ~MyClass() const
actually makes more sense. The destructor doesn't have to modify anyhting, only destroy the object as if it were no longer a valid handle to whatever resource it controlled.
推荐答案
Imho您已经确定了真正的需求.
Imho you have identified a real need.
Your solution sounds a lot like what I have called destructive move semantics. This possibility is described in the original move semantics proposal. I think such a design is possible, though it is not without its problems. As far as I know, no one is working this area on the standards committee.
有一些更简单的方法可以从关联容器中提取仅移动类型,而无需更改语言(除了允许在没有未定义行为的情况下进行类型修饰之外).
There are simpler ways to extract move-only types out of the associative containers that would not require language changes (aside maybe from allowing type-punning without undefined behavior).
N3645 是仅库建议,将嵌套的node_ptr
类型放入每个容器中. node_ptr
非常类似于unique_ptr
.它在关联容器中具有节点的唯一所有权.但是,当取消引用它时,您将获得对节点中的value_type
的非常量访问,而不是节点本身. extract
和insert
成员被添加到关联的容器中,从而使一个成员可以向容器中插入节点(由node_ptr
拥有)或从中删除节点.
N3645 is a library-only proposal which puts a nested node_ptr
type into each container. The node_ptr
is a lot like a unique_ptr
. It has unique ownership of a node in an associative container. But when you dereference it, you get non-const access to the value_type
in the node, instead of the node itself. extract
and insert
members are added to the associative containers allowing one to insert and remove nodes (owned by the node_ptr
) to/from the containers.
您可以使用它从容器中删除节点,然后将仅移动类型移出该节点,并在完成操作后让~node_ptr()
清理该节点.本文包含了用于演示此功能的示例:
You could use this to remove a node from a container, and then move a move-only type out of the node, and let ~node_ptr()
clean up the node when you are done with it. The paper includes this example to demonstrate this functionality:
set<move_only_type> s;
s.emplace(...);
move_only_type mot = move(*s.extract(s.begin())); // extract, move, deallocate node
请注意,s.extract
是noexcept
,当然也是~node_ptr()
.如果move_only_type
的移动结构为noexcept
,则整个操作为noexcept
.否则,如果抛出移动构造,则将set
保留为已从set
中删除该项目.
Note that s.extract
is noexcept
, as is ~node_ptr()
of course. If the move construction of move_only_type
is noexcept
, then this whole operation is noexcept
. Otherwise if the move construction throws, the set
is left as if the item had been erased from the set
.
At the moment, no progress is being made on N3645. It has not been voted into a working draft, and I have no confidence that it ever will be.
更新C ++ 17
I stand corrected: The functionality I describe above was voted into C++17 with P0083R3. Thanks to Cosme for reminding me of this in the comments below.
这篇关于移动语义是否不完整?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!