Many times, we write operator = functions of the class (for example, when the class contains pointers ).
Consider the following class:
class Widget {public: Widget(int x=0): val(new int(x)) {} ~Widget() { delete val; } Widget(const Widget &rhs): val(new int(*rhs.val)) {} //operator = Widget& operator=(const Widget &rhs); void print() const { cout << *val << endl; }private: int *val;};
Incorrect version: the following code is insecure when you assign values to yourself. If * This and RHS are the same object, the first statement is delete val;
Not only does the Val of the current object be deleted, but the Val of RHS is also deleted. RHS. Val points to a deleted int, which inevitably produces a strange problem.
/** wrong version * not-safe when self-assignment occurs. */Widget& Widget::operator=(const Widget &rhs) { delete val; val = new int(*rhs.val); return *this;}
Improved Version 1: the traditional way to prevent such errors is to add an identity test ).
Widget& Widget::operator=(const Widget &rhs) { if(this == &rhs) return; delete val; val = new int(*rhs.val); return *this;}
However, although the above practices are self-replication secure, they do not have exceptional security.
If the new int throws an exception, this-> Val points to a deleted Int.
Improved Version 2: Both exception security and self-replication Security
Widget& Widget::operator=(const Widget &rhs) { int *pOld = val; val = new int(*rhs.val); delete pOld; return *this;}
Improved Version 3: Copy and swap Technology
Widget& Widget::operator=(const Widget &rhs) { Widget temp(rhs); swap(temp); return *this;}
Improved Version 4: Copy and swap by passing values
Widget& Widget::operator=(Widget rhs) { //yes, copy by value swap(rhs); return *this;}