Mat*_*lia 13 c++ move-semantics c++11 move-assignment-operator
关于移动分配的标准库策略是允许实现假设永远不会发生自我分配 ; 在我看来这是一个非常糟糕的主意,因为:
remove_if
家庭中的任何事情都需要照顾这个角落的情况;那么,为什么这样的决定呢?
¹特别是在库代码中,实现者可以自由地利用关于"分支预期结果"的编译器特定提示(在VC++ __builtin_expect
中的gcc/__assume
中).
从std
应该被丢弃的对象移动或在被重用之前被分配. 任何不完全自由的东西都不会被承诺.
有时事情是免费的.就像一个移动构造的容器是空的.请注意,某些移动辅助的情况没有这样的保证,因为某些实现可能会选择移动元素而不是缓冲区.为什么不同?一个是免费的额外保证,另一个不是.
分支机构或其他支票不是完全免费的.它占用了一个分支预测槽,即使预测它几乎是免费的.
最重要的是,a = std::move(a);
是逻辑错误的证据.分配 - 来自a
(内std
)意味着您只会分配或丢弃a
.然而,在这里,你希望它在下一行具有特定的状态.要么你知道你是自我分配,要么你不知道.如果你不这样做,你现在正在从你正在填充的对象移动,而你却不知道它.
"做一件小事以保证安全"的原则与"你不为你不使用的东西付钱"相冲突.在这种情况下,第二个赢了.
Yakk给出了一个很好的答案(与往常一样并被赞成),但是这次我只想补充一点信息。
在过去的五年中,自我分配的政策发生了微小的变化。我们刚刚在LWG 2468中阐明了这种极端情况。实际上,我应该更加精确:两次会议之间的一个非正式小组同意解决该问题,下个月(2016年11月)很可能将其投票通过C ++ 1z工作草案。
问题的要点是修改MoveAssignable
要求以阐明如果移动分配的目标和源是同一对象,则分配后对对象的值没有任何要求(除非它必须是有效状态) )。它进一步阐明,如果将此对象与std :: lib一起使用,则无论它是移动分配还是自移动分配,它仍必须满足算法的要求(例如LessThanComparable
)。
所以...
T x, y;
x = std::move(y); // The value of y is unspecified and x == the old y
x = std::move(x); // The value of x is unspecified
Run Code Online (Sandbox Code Playgroud)
但是两者x
和y
仍处于有效状态。没有内存泄漏。没有发生未定义的行为。
此职位的理由
它仍然是性能。但是,公认的是swap(x, x)
自C ++ 98起合法,并且确实发生在野外。此外,由于C ++ 11 swap(x, x)
在以下位置执行自移动分配x
:
T temp = std::move(x);
x = std::move(x);
x = std::move(temp);
Run Code Online (Sandbox Code Playgroud)
在C ++ 11之前,swap(x, x)
是(相当昂贵的)无操作(使用复制而不是移动)。 LWG 2468阐明,在C ++ 11及之后的版本中,swap(x, x)
仍然是(不是很贵)无操作(使用move而不是copy)。
细节:
T temp = std::move(x);
// temp now has the value of the original x, and x's value is unspecified
x = std::move(x);
// x's value is still unspecified
x = std::move(temp);
// x's value now has the value of temp, which is also the original x value
Run Code Online (Sandbox Code Playgroud)
要实现此无操作,x
只要将其x
置于有效状态而不声明或引发异常,就可以进行自我移动分配。
如果要为您的类型指定T
self-move-assignment为no-op,那就很好了。std :: lib正是针对unique_ptr
。
如果您想为自己的类型指定U
self-move-assignment使其处于有效但未指定的状态,那也可以。std :: lib正是针对vector
。一些实现(我相信VS)会在vector
无操作上进行自我分配。其他则没有(例如libc ++)。
归档时间: |
|
查看次数: |
953 次 |
最近记录: |