C++核心准则C.65:让移动操作对自赋值安全

面向对象思考

共 2738字,需浏览 6分钟

 ·

2020-01-13 23:24

b6afb0134384b786b96a526900f2ad2d.webp

白钨矿

C.65: Make move assignment safe for self-assignment
C.65:让移动操作对自赋值安全a2842c9728109f52fc994690f2a7b2ab.webp
Reason(原因)

If x = x changes the value of x, people will be surprised and bad errors may occur. However, people don't usually directly write a self-assignment that turn into a move, but it can occur. However, std::swap is implemented using move operations so if you accidentally do swap(a, b) where a and b refer to the same object, failing to handle self-move could be a serious and subtle error.

如果x=x改变了x的值,人们会感到诧异而且有可能发生严重的错误。虽然人们一般不会直接在移动操作中使用自赋值,它还是会发生。但是由于std::swap被实现为使用移动操作,如果你意外地调用了swap(a,b)而a和b参照了同一个对象,如果没有处理好自赋值的话,可能会发生严重且不易发现的错误。


a2842c9728109f52fc994690f2a7b2ab.webp
Example(示例)

class Foo {
   string s;
   int i;
public:
   Foo& operator=(Foo&& a);
   // ...
};

Foo& Foo::operator=(Foo&& a) noexcept  // OK, but there is a cost
{
if (this == &a) return *this;  // this line is redundant
   s = std::move(a.s);
   i = a.i;
   return *this;
}

The  one-in-a-million argument againstif (this == &a) return *this; tests from the discussion of self-assignment is even more relevant for self-move.

违反自我赋值检查的概率只有百万分之一(数据只要领会精神就好,译者注);避免自我赋值的讨论和自我移动的关系更加密切。


a2842c9728109f52fc994690f2a7b2ab.webp
Note(注意)

There is no known general way of avoiding an if (this == &a) return *this; test for a move assignment and still get a correct answer (i.e., after x = x the value of x is unchanged).

没有避免使用if(this==&a)return *this;操作的普遍办法。检查移动赋值的方法仍然会得出正确的结果(例如在x=x之后x的值不会改变)。


a2842c9728109f52fc994690f2a7b2ab.webp
Note(注意)

The ISO standard guarantees  only a "valid but unspecified" state for the standard-library containers. Apparently this has not been a problem in about 10 years of experimental and production use. Please contact the editors if you find a counter example. The rule here is more caution and insists on complete safety.

ISO标准只为标准库容易保证了一个“合法但未定义”的状态。看起来在10多年的经验和产品应用中没有成为问题。如果你遇到了反例请联系编辑。本规则更为谨慎并坚持做到完全安全。


a2842c9728109f52fc994690f2a7b2ab.webp
Example(示例)

Here is a way to move a pointer without a test (imagine it as code in the implementation a move assignment):

这里有一个不检查就移动指针的方法(将其想象为实现移动赋值代码中的一部分):

// move from other.ptr to this->ptr
T* temp = other.ptr;
other.ptr = nullptr;
delete ptr;
ptr = temp;

译者注

如果other和this是同一个对象,other.ptr=nullptr也会同时将this.ptr置空,导致下面的delete ptr不起作用。这样就保证了自我移动时的安全。

这种做法太难理解了。

a2842c9728109f52fc994690f2a7b2ab.webp
Enforcement(示例)
  • (Moderate) In the case of self-assignment, a move assignment operator should not leave the object holding pointer members that have been deleted or set to nullptr.

  • (中等)在自赋值的情况下,移动操作运算符应该避免对象的指针成员指向的对象被销毁或者该指针成员被置空。

  • (Not enforceable) Look at the use of standard-library container types (incl. string) and consider them safe for ordinary (not life-critical) uses.

  • (无法实施)找到使用标准库容器类型(包括string),认为它们在通常用途(不是声明周期敏感)时安全的。

a2842c9728109f52fc994690f2a7b2ab.webp
原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c65-make-move-assignment-safe-for-self-assignment




觉得本文有帮助?请分享给更多人。

关注【面向对象思考】轻松学习每一天!

面向对象开发,面向对象思考!

浏览 26
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报