CppCoreGuidelines C.65 确保可以安全的自己赋值给自己
31 October 2022
“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; }
注意
ISO 标准只保障标准库容器的状态是“有效的,但不明确指定”。显然,在十多年的实验和产品使用过程中,不是什么大问题。这条指南更强调完全的安全。
例子
这个例子展示了不需要进行测试的情况下,移动一个指针。可以认为是 move 操作的一个实现方法:
// move from other.ptr to this->ptr T* temp = other.ptr; other.ptr = nullptr; delete ptr; ptr = temp;
强化
- (适度)在自赋值的情况,移动赋值操作不能删除对象的指针成员或设置成 nullptr。
- (不是强制的)查看标准库容器类型的使用方法,包括 string。确保在一般的使用过程中是安全的。