Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: REM Cost Reform

...

Code Block
bgColor#FFcccc
langcpp
#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
bgColor#ccccff
langcpp
#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
bgColor#ccccff
langcpp
#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;
  }
};

Compliant Solution (Move and Swap)

This compliant solution uses the same classes S and T from the previous compliant solution, but adds the following public constructor and methods:

Code Block
bgColor#ccccff
langcpp
  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;
  }

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.

The move constructor is not strictly necessary, but defining a move constructor along with a move assignment operator is conventional for classes that support move operations.

Note that unlike copy assignment operators, the signature of a move assignment operator accepts a non-const reference to its object with the expectation that the moved-from object will be left in an unspecified, but valid state. Move constructors have the same difference from copy constructors.

Risk Assessment

Allowing a copy assignment operator to corrupt an object could lead to undefined behavior.

Rule

Severity

Likelihood

Remediation Cost

Detectable

Repairable

Priority

Level

OOP54-CPP

Low

Probable

High

Yes

No

P2

P4

L3

Automated Detection

Tool

Version

Checker

Description

Parasoft C/C++test9.5OOP-34 PRQA QA-C++ Include PagePRQA QA-C++_VPRQA QA-C++_V4072, 4073, 4075, 4076 

Astrée

Include Page
Astrée_V
Astrée_V

dangling_pointer_use

Clang
9.0 (r361550)
cert-oop54-cppChecked by clang-tidy.
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

IO.DC
ALLOC.DF
ALLOC.LEAK
LANG.MEM.NPD
LANG.STRUCT.RC
IO.UAC
ALLOC.UAF

Double Close
Double Free
Leak
Null Pointer Dereference
Redundant Condition
Use After Close
Use After Free

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C++4072, C++4073, C++4075, C++4076


Klocwork
Include Page
Klocwork_V
Klocwork_V
CL.SELF-ASSIGN
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_CPP-OOP54-a

User-provided copy assignment operators shall handle self-assignment
Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C++: OOP54-CPPChecks for copy assignment operators where self-assignment is not tested (rule partially covered)

Related Vulnerabilities

Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

...

This rule is a partial subset of OOP58-CPP. Copy operations must not mutate the source object when copy operations do not gracefully handle self-copy assignment, because the copy operation may mutate both the source and destination objects (due to them being the same object).

Bibliography

[Henricson
97
1997]Rule 5.12, Copy assignment operators should be protected from doing destructive actions if an object is assigned to itself
[ISO/IEC 14882-2014]Subclause 17.6.3.1, "Template Argument Requirements"
Subclause 17.6.4.9, "Function Arguments"
[Meyers
05
2005]Item 11, "Handle Assignment to Self in operator="
[Meyers
14
2014]
 

...



...

Image Modified Image Modified Image Modified