自我指派保护

在编写复制赋值运算符时,非常重要的是它能够在自我赋值的情况下工作。也就是说,它必须允许这样:

SomeType t = ...;
t = t;

自我分配通常不会以这种显而易见的方式发生。它通常通过各种代码系统的迂回路径发生,其中赋值的位置只有两个 Person 指针或引用,并且不知道它们是同一个对象。

你编写的任何复制赋值运算符都必须考虑到这一点。

这样做的典型方法是将所有赋值逻辑包装在如下的条件中:

SomeType &operator=(const SomeType &other)
{
    if(this != &other)
    {
        //Do assignment logic.
    }
    return *this;
}

注意: 考虑自我分配并确保代码在发生时正常运行很重要。然而,自我分配是非常罕见的,并且优化以防止它可能实际上使正常情况变得悲观。由于正常情况更为常见,因此对自我分配感到悲观可能会降低代码效率(因此请小心使用它)。

例如,实现赋值运算符的常规技术是 copy and swap idiom。这种技术的正常实现并不打算测试自我分配(即使由于复制而自我分配也很昂贵)。原因是正常情况的悲观化已被证明成本更高(因为它经常发生)。

Version >= C++ 11

还必须保护移动赋值运算符以防止自我赋值。然而,许多这样的运算符的逻辑基于 std::swap,它可以处理从/到相同内存的交换。因此,如果你的移动分配逻辑只是一系列交换操作,那么你不需要自我分配保护。

如果不是这种情况,你必须采取与上述类似的措施。