31 October 2022

C++ 核心指南目录

“Make move assignment safe for self-assignment”

理由

如果 x = x 会改变 x 的值,人们会觉得震惊,会引起出错。虽然,人们通常不会直接通过移动(move)来写自赋值操作,但是有些情况会使用移动操作。比如 std::swap 是通过移动操作实现的,如果你在处理 swap(a, b) 的时候,不小心让 ab 指向了同一个对象。这时候,错误的自移动操作会导致很难发现的严重故障。

例子

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。确保在一般的使用过程中是安全的。