在编写复制赋值运算符时,它能够在自赋值的情况下工作是非常重要的。也就是说,它必须允许:
SomeType t = ...; t = t;
自我分配通常不会以如此明显的方式发生。它通常通过各种代码系统的迂回路线发生,其中赋值的位置只有两个Person指针或引用,并且不知道它们是同一个对象。
您编写的任何复制赋值运算符都必须能够考虑到这一点。
这样做的典型方法是将所有赋值逻辑包装在这样的条件中:
SomeType &operator=(const SomeType &other) { if(this != &other) { //做赋值逻辑。 } return *this; }
注意:考虑自赋值并确保您的代码在发生时正确运行非常重要。然而,自赋值是一种非常罕见的情况,优化以防止它实际上可能会使正常情况变得悲观。由于正常情况更为常见,悲观自赋值可能会降低您的代码效率(因此请谨慎使用)。
例如,实现赋值运算符的常规技术是copy and swap idiom. 这种技术的正常实现不会费心测试自赋值(即使自赋值很昂贵,因为制作了副本)。原因是对正常情况的悲观化已被证明成本更高(因为它发生得更频繁)。
移动赋值运算符也必须受到保护以防止自赋值。但是,许多此类运算符的逻辑基于std::swap,它可以很好地处理从/到同一内存的交换。所以如果你的移动赋值逻辑不过是一系列的交换操作,那么你就不需要自赋值保护了。
如果不是这种情况,您必须采取与上述类似的措施。