Effective C++——Item11: 在operator=()中处理自赋值问题

发布时间 2023-10-07 10:23:48作者: 偷不走的影子

Item11: 在operator=()中处理自赋值问题

一、自赋值发生的时机:

  1. w = w,看起来不太可能发生,但可能隐式出现。
  2. a[i] = a[j],可能发生在数组循环中。
  3. *p1 = *p2, p1 和 p2可能是来自一个继承体系中,指向相同对象的不同指针。

二、不安全实现:自赋值不安全,异常不安全

Widget& Widget::operator=(const Widget& rhs)          
{
  delete pb;                                     
  pb = new Bitmap(*rhs.pb);                      
  return *this;                                 
}

二、解决自赋值安全

在 operator= 的开始处通过一致性检测来阻止自赋值


Widget& Widget::operator=(const Widget& rhs)
{
  if (this == &rhs) 
  	return *this;  
                                   
  delete pb;
  pb = new Bitmap(*rhs.pb);

  return *this;
}

但未解决异常安全

如果 "new Bitmap" 表达式引发一个异常(可能因为供分配的内存不足或者因为 Bitmap 的拷贝构造函数抛出一个异常),Widget 将以持有一个指向被删除的 Bitmap 的指针而告终。这样的指针是你不能安全地删除它们,你甚至不能安全地读取它们。

三、尝试忽略它

如果 "new Bitmap" 抛出一个异常,pb 以及它所在的 Widget 的遗迹没有被改变。甚至不需要一致性检测,这里的代码也能处理自赋值,因为我们做了一个原始位图的拷贝,删除原始位图,然后指向我们作成的拷贝。这可能不是处理自赋值的最有效率的做法,但它能够工作。

Widget& Widget::operator=(const Widget& rhs)
{
  Bitmap *pOrig = pb;              
  pb = new Bitmap(*rhs.pb);        
  delete pOrig;                   

  return *this;
}

四、 "copy and swap" 的技术——实现异常和自赋值安全的方法


class Widget {
  ...
  void swap(Widget& rhs);      
  ...                         
};

Widget& Widget::operator=(const Widget& rhs)
{
  Widget temp(rhs);            
  swap(temp);                  
  return *this;
}

五、如果类成员含有的unique_ptr指针,而没有raw pointer,那么在它的赋值运算符函数中不处理自赋值问题会有什么问题吗?

如果类成员只有std::unique_ptr,而没有裸指针,那么在赋值运算符函数中不处理自赋值问题是没有问题的。

原因如下:

std::unique_ptr的赋值操作会自动处理自赋值问题。当一个std::unique_ptr被赋值时,原有的内存将被自动删除,然后才会接管新的内存。

举例来说,假设有以下的代码:

class Foo {
public:
    std::unique_ptr<int> ptr;

    Foo& operator=(const Foo& other) {
        if (this != &other) {
            ptr = std::make_unique<int>(*other.ptr);
        }
        return *this;
    }
}; 

即使不进行自赋值检查,当进行自赋值时,std::unique_ptr的赋值操作也不会导致问题。这是因为std::unique_ptr的赋值操作会首先删除当前的内存,然后再分配新的内存。因此,即使是自赋值,也不会有问题。

然而,这不意味着在所有的情况下都可以忽略自赋值检查。如果类成员是裸指针或者其他需要手动管理内存的资源,那么就必须在赋值运算符函数中处理自赋值问题,以防止内存泄露或者其他问题。