CppCoreGuidelines C.65 确保可以安全的自己赋值给自己
31 October 2022
C.65: Make move assignment safe for self-assignment
理由
如果x = x
会改变 x
的值,人们会觉得震惊,会引起出错。虽然,人们通常不会直接通过移动( move )来写自赋值操作,但是有些情况会使用移动操作。比如std::swap
是通过移动操作实现的,如果你在处理swap(a, b)
的时候,不小心让 a
和 b
指向了同一个对象。这时候,错误的自移动操作会导致很难发现的严重故障。
例子
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; }
这一行语句if (this == &a) return *this;
并没太大作用,反而会使得程序变慢。
注意
ISO 标准只保障标准库容器的状态是“有效的状态,但不明确指定是什么状态”。显然,在十多年的实验和产品使用过程中,不是什么大问题。这条指南更强调完全的安全。
例子
这个例子展示了不需要进行测试的情况下,移动一个指针。可以认为是 move 操作的一个实现方法:
// move from other.ptr to this->ptr T* temp = other.ptr; other.ptr = nullptr; delete ptr; ptr = temp;
强化
- (适度)在自赋值的情况下,移动赋值操作不能删除对象的指针成员,或把它设置成
nullptr
。 - (不是强制的)查看标准库容器类型的使用方法,包括
string
。确保在普通的使用过程中是安全的。