summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-self-assignment.rst
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-self-assignment.rst')
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-self-assignment.rst116
1 files changed, 116 insertions, 0 deletions
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-self-assignment.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-self-assignment.rst
new file mode 100644
index 00000000000..64412ba0494
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-self-assignment.rst
@@ -0,0 +1,116 @@
+.. title:: clang-tidy - bugprone-unhandled-self-assignment
+
+bugprone-unhandled-self-assignment
+==================================
+
+Finds user-defined copy assignment operators which do not protect the code
+against self-assignment either by checking self-assignment explicitly or
+using the copy-and-swap or the copy-and-move method.
+
+This check now searches only those classes which have any pointer or C array field
+to avoid false positives. In case of a pointer or a C array, it's likely that self-copy
+assignment breaks the object if the copy assignment operator was not written with care.
+
+See also:
+`OOP54-CPP. Gracefully handle self-copy assignment
+<https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP54-CPP.+Gracefully+handle+self-copy+assignment>`_
+
+A copy assignment operator must prevent that self-copy assignment ruins the
+object state. A typical use case is when the class has a pointer field
+and the copy assignment operator first releases the pointed object and
+then tries to assign it:
+
+.. code-block:: c++
+
+ 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);
+ return *this;
+ }
+ };
+
+There are two common C++ patterns to avoid this problem. The first is
+the self-assignment check:
+
+.. code-block:: c++
+
+ 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;
+ }
+ };
+
+The second one is the copy-and-swap method when we create a temporary copy
+(using the copy constructor) and then swap this temporary object with ``this``:
+
+.. code-block:: c++
+
+ 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;
+ }
+ };
+
+There is a third pattern which is less common. Let's call it the copy-and-move method
+when we create a temporary copy (using the copy constructor) and then move this
+temporary object into ``this`` (needs a move assignment operator):
+
+.. code-block:: c++
+
+ 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;
+ }
+ };
OpenPOWER on IntegriCloud