...
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <new>
struct S { S(const S &) noexcept; /* ... */ }; // Has nonthrowing copy constructor
class T {
int n;
S *s1;
public:
T(const T &rhs) : n(rhs.n), s1(rhs.s1 ? new S(*rhs.s1) : nullptr) {}
~T() { delete s1; }
// ...
T& operator=(const T &rhs) {
n = rhs.n;
delete s1;
s1 = new S(*rhs.s1);
return *this;
}
}; |
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <new>
struct S { S(const S &) noexcept; /* ... */ }; // Has nonthrowing copy constructor
class T {
int n;
S *s1;
public:
T(const T &rhs) : n(rhs.n), s1(rhs.s1 ? new S(*rhs.s1) : nullptr) {}
~T() { delete s1; }
// ...
T& operator=(const T &rhs) {
if (this != &rhs) {
n = rhs.n;
delete s1;
try {
s1 = new S(*rhs.s1);
} catch (std::bad_alloc &) {
s1 = nullptr; // For basic exception guarantees
throw;
}
}
return *this;
}
};
|
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <new>
#include <utility>
struct S { S(const S &) noexcept; /* ... */ }; // Has nonthrowing copy constructor
class T {
int n;
S *s1;
public:
T(const T &rhs) : n(rhs.n), s1(rhs.s1 ? new S(*rhs.s1) : nullptr) {}
~T() { delete s1; }
// ...
void swap(T &rhs) noexcept {
using std::swap;
swap(n, rhs.n);
swap(s1, rhs.s1);
}
T& operator=(const T &rhs) noexcept {
T(rhs).swap(*this);
return *this;
}
}; |
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
T(T &&rhs) { *this = std::move(rhs); }
// ... everything except operator= ..
T& operator=(T &&rhs) noexcept {
using std::swap;
swap(n, rhs.n);
swap(s1, rhs.s1);
return *this;
}
T& operator=(const T &rhs) {
T temp(rhs);
*this = std::move(temp);
return *this;
} |
The copy assignment operator uses std::move() rather than swap() to achieve safe self-assignment and a strong exception guarantee. The move assignment operator uses a move (via the method parameter) and swap.
...
Allowing a copy assignment operator to corrupt an object could lead to undefined behavior.
Rule | Severity | Likelihood | Detectable | Remediation CostRepairable | Priority | Level |
|---|---|---|---|---|---|---|
OOP54-CPP | Low | Probable | Yes | HighNo | P2P4 | L3 |
Automated Detection
Tool | Version | Checker | Description | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Astrée |
| dangling_pointer_use | ||||||||||||
| Clang | 9.0 (r361550) | cert-oop54-cpp | Checked by clang-tidy. | |||||||||||
| CodeSonar |
| IO.DC | Double Close | |||||||||||
| Helix QAC |
| C++4072, C++4073, C++4075, C++4076 | ||||||||||||
| Klocwork |
| CL.SELF-ASSIGN | ||||||||||||
| Parasoft C/C++test |
| CERT_CPP-OOP54-a | Check for assignment to self in operator= | User-provided copy assignment operators shall handle self-assignment | ||||||||||
| Polyspace Bug Finder |
| CERT C++: OOP54-CPP | Checks for copy assignment operators where self-assignment is not tested (rule partially covered) | PRQA QA-C++ | | Include Page | | PRQA QA-C++_V | PRQA QA-C++_V | 4072, 4073, 4075, 4076
Related Vulnerabilities
Search for other vulnerabilities resulting from the violation of this rule on the CERT website.
...