标准库中自赋值不安全的移动赋值运算符的基本原理是什么? [英] What is the rationale for self-assignment-unsafe move assignment operators in the standard library?

查看:110
本文介绍了标准库中自赋值不安全的移动赋值运算符的基本原理是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于移动分配的标准库政策是:允许实现假定自赋值永远不会发生;在我看来,这是一个非常糟糕的主意,因为:

The standard library policy about move assignment is that the implementation is allowed to assume that self-assignment will never happen; this seems to me a really bad idea, given that:

  • C ++中的常规"(副本")转让合同一直被视为可以避免自我转让;现在,我们还有另外一个不连贯的C ++特例需要记忆和解释-还有一个微妙的危险.我想我们都同意,C ++所需的不是 更多隐藏的陷阱;
  • 它使算法复杂化-remove_if系列中的任何东西都需要照顾这种极端情况;
  • 真正满足此要求非常容易-您可以免费实现带有swap的move动作,即使在其他情况下(可以通过即席逻辑获得一些性能提升),它也只是一个(几乎)从未采取过分支,这实际上在任何CPU上都是免费的¹;同样,在最有趣的情况下(涉及参数或局部变量的移动),优化器在进行内联时会完全删除分支(对于简单"移动赋值运算符几乎总是会发生这种情况.)
  • the "regular" ("copy") assignment contract in C++ has always been regarded as safe against self-assignment; now we have yet another incoherent corner case of C++ to remember and to explain - and a subtly dangerous one, too; I think we all agree that what is needed in C++ is not more hidden traps;
  • it complicates algorithms - anything in the remove_if family need to take care of this corner case;
  • it would be really easy to fulfil this requirement - where you implement move with swap it comes for free, and even in other cases (where you can get some performance boost with ad-hoc logic) it's just a single, (almost) never taken branch, which is virtually free on any CPU¹; also, in most interesting cases (moves involving parameters or locals) the branch would be removed completely by the optimizer when inlining (which should happen almost always for "simple" move assignment operators).

那么,为什么要做出这样的决定?

So, why such a decision?

¹特别是在库代码中,实现者可以自由地利用有关分支预期结果"的特定于编译器的提示(在VC ++中,请考虑gcc/__assume中的__builtin_expect).

¹ Especially in library code, where implementers can liberally exploit compiler-specific hints about "branch expected outcome" (think __builtin_expect in gcc/__assume in VC++).

推荐答案

std中的对象移动而来的对象应该被丢弃或分配给它们,然后再使用.除了承诺之外的任何不完全免费的任何.

Moved from objects in std are supposed to be discarded or assigned to prior to being reused. Anything that is not completely free beyond that is not promised.

有时候事情是免费的.就像从容器移动构造而成的容器是空的.请注意,某些移动辅助的情况没有这种保证,因为某些实现可能选择移动元素而不是缓冲区.为什么会有所不同?一个是免费的额外保证,另一个不是.

Sometimes things are free. Like a move-constructed-from container is empty. Note that some move-assiged-from cases have no such guarantee, as some implementations may choose to move elements instead of buffers. Why the difference? One was a free extra guarantee, the other not.

分支机构或其他支票并非完全免费.它占用了一个分支预测时隙,即使预测几乎是免费的.

A branch or other check is not completely free. It takes up a branch prediction slot, and even if predicted is merely almost free.

最重要的是,a = std::move(a);是逻辑错误的证据.从a分配(在std内)意味着您将仅分配或放弃a.但是在这里,您希望它在下一行具有特定状态.您要么知道自己正在自我分配,要么就不知道.如果不这样做,那么您现在正在从也正在填充的对象移开,而您却不知道.

On top of that, a = std::move(a); is evidence of a logic error. Assign-from a (within std) means you will only assign-to or discard a. Yet here you are wanting it to have specific state on the next line. Either you know you are self-assigning, or you do not. If you do not, you are now moving from object you are also populating and you do not know it.

做些小事以确保事情安全"的原则与您不为不使用的商品支付费用"相抵触.在这种情况下,第二个获胜.

The principle of "do little things to keep things safe" clashes with "you do not pay for that which you do not use". In this case, the second won.

这篇关于标准库中自赋值不安全的移动赋值运算符的基本原理是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆