131 lines · plain
1.. title:: clang-tidy - bugprone-unhandled-self-assignment2 3bugprone-unhandled-self-assignment4==================================5 6`cert-oop54-cpp` redirects here as an alias for this check. For the CERT alias,7the `WarnOnlyIfThisHasSuspiciousField` option is set to `false`.8 9Finds user-defined copy assignment operators which do not protect the code10against self-assignment either by checking self-assignment explicitly or11using the copy-and-swap or the copy-and-move method.12 13By default, this check searches only those classes which have any pointer or C14array field to avoid false positives. In case of a pointer or a C array, it's15likely that self-copy assignment breaks the object if the copy assignment16operator was not written with care.17 18See also:19`OOP54-CPP. Gracefully handle self-copy assignment20<https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP54-CPP.+Gracefully+handle+self-copy+assignment>`_21 22A copy assignment operator must prevent that self-copy assignment ruins the23object state. A typical use case is when the class has a pointer field24and the copy assignment operator first releases the pointed object and25then tries to assign it:26 27.. code-block:: c++28 29 class T {30 int* p;31 32 public:33 T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}34 ~T() { delete p; }35 36 // ...37 38 T& operator=(const T &rhs) {39 delete p;40 p = new int(*rhs.p);41 return *this;42 }43 };44 45There are two common C++ patterns to avoid this problem. The first is46the self-assignment check:47 48.. code-block:: c++49 50 class T {51 int* p;52 53 public:54 T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}55 ~T() { delete p; }56 57 // ...58 59 T& operator=(const T &rhs) {60 if(this == &rhs)61 return *this;62 63 delete p;64 p = new int(*rhs.p);65 return *this;66 }67 };68 69The second one is the copy-and-swap method when we create a temporary copy70(using the copy constructor) and then swap this temporary object with ``this``:71 72.. code-block:: c++73 74 class T {75 int* p;76 77 public:78 T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}79 ~T() { delete p; }80 81 // ...82 83 void swap(T &rhs) {84 using std::swap;85 swap(p, rhs.p);86 }87 88 T& operator=(const T &rhs) {89 T(rhs).swap(*this);90 return *this;91 }92 };93 94There is a third pattern which is less common. Let's call it the copy-and-move95method when we create a temporary copy (using the copy constructor) and then move96this temporary object into ``this`` (needs a move assignment operator):97 98.. code-block:: c++99 100 class T {101 int* p;102 103 public:104 T(const T &rhs) : p(rhs.p ? new int(*rhs.p) : nullptr) {}105 ~T() { delete p; }106 107 // ...108 109 T& operator=(const T &rhs) {110 T t = rhs;111 *this = std::move(t);112 return *this;113 }114 115 T& operator=(T &&rhs) {116 p = rhs.p;117 rhs.p = nullptr;118 return *this;119 }120 };121 122Options123-------124 125.. option:: WarnOnlyIfThisHasSuspiciousField126 127 When `true`, the check will warn only if the container class of the copy128 assignment operator has any suspicious fields (pointer, C array and C++ smart129 pointer).130 This option is set to `true` by default.131