User-defined copy assignment operators that do not protect against self-assignment can result in undefined behavior and memory leaks.
This check detects such copy assignment operators and suggests two common patterns to handle self-assignment: the self-assignment check and the copy-and-swap method.
class T {
int* p;
public:
T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}
~T() { delete p; }
// ...
T& operator=(const T &rhs) {
delete p;
p = new int(*rhs.p); // possibly a self swap, check for rhs == this
return *this;
}
};
class T {
int* p;
public:
T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}
~T() { delete p; }
// ...
T& operator=(const T &rhs) {
if(this == &rhs)
return *this;
delete p;
p = new int(*rhs.p);
return *this;
}
};
class T {
int* p;
public:
T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}
~T() { delete p; }
// ...
void swap(T &rhs) {
using std::swap;
swap(p, rhs.p);
}
T& operator=(const T &rhs) {
T(rhs).swap(*this);
return *this;
}
};
class T {
int* p;
public:
T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}
~T() { delete p; }
// ...
T& operator=(const T &rhs) {
T t = rhs;
*this = std::move(t);
return *this;
}
T& operator=(T &&rhs) {
p = rhs.p;
rhs.p = nullptr;
return *this;
}
};