Rule A12-8-5 (required, implementation, automated)
A copy assignment and a move assignment operators shall handle self-assignment.
Rationale
User-defined copy assignment operator and move assignment operator need to prevent self-assignment, so the operation will not leave the object in an indeterminate state. If the given parameter is the same object as the local object, destroying objectlocal resources will invalidate them. It violates the copy/move assignment postconditions. Note that STL containers assume that self-assignment of an object is correctly handled. Otherwise it may lead to unexpected behavior of an STL container.
Self-assignment problem can also be solved using swap operators. See rule: A12-8-2.
Example
// $Id: A12-8-5.cpp 271773 2017-03-23 13:16:53Z piotr.tanski $
#include <cstdint>
#include <stdexcept>
struct A
{
std::int32_t number;
std::int32_t* ptr;
// Implementation
};
class B
{
public:
// ...
B& operator=(B const& oth) // Non-compliant
{
i = oth.i;
delete aPtr;
try
{
aPtr = new A(*oth.aPtr); // If this is the self-copy
// the oth.a_ptr is already
case, then
deleted
}
catch (std::bad_alloc&)
{
aPtr = nullptr;
}
return *this;
}
private:
std::int16_t i = 0;
A* aPtr = nullptr;
};
class C
{
public:
C& operator=(C const& oth) // Compliant
{
if (this != &oth)
{
A* tmpPtr = new A(*oth.aPtr);
i = oth.i;
delete aPtr;
aPtr = tmpPtr;
}
return *this;
}
C& operator=(C&& oth) // Compliant
{
if (this != &oth)
{
A* tmpPtr = new A{std::move(*oth.aPtr)};
i = oth.i;
delete aPtr;
aPtr = tmpPtr;
}
return *this;
}
private:
std::int16_t i = 0;
A* aPtr = nullptr;
};
See also
SEI CERT C++ [10]: OOP54-CPP Gracefully handle self-assignment. C++ Core Guidelines [11]: C.62: Make copy assignment safe for self-assignment.