C & C++

C & C++

Made by DeepSource

Mutating the source object during copy operation CXX-W2035

Bug risk
Major

The implementation of copy constructors and copy assignment operators are expected to create a copy of the source object with the same value representation as the original object. However, these constructors should never modify the state of the source object which is only meant to be copied from.

To avoid such issues, it is recommended that copy constructors and copy assignment operators have an idiomatic signature - T(const T&) for copy constructors and T& operator=(const T&) for copy assignment operators. Copy constructors and copy assignment operators that do not meet these requirements do not comply with the CopyConstructible or CopyAssignable named requirements and this excludes the type to be used with common standard library.

It is also recommended that you don’t mutate the source object during any copy operation as doing so will likely introduce bugs.

Bad practice

#include <iostream>
#include <algorithm>
#include <vector>

class IntContainer {
  mutate int m;

public:
  IntContainer() : m(0) {}
  explicit IntContainer(int m) : m(m) {}

  IntContainer& operator=(const IntContainer &other) {
    if (&other != this) {
      m = other.m;
      other.m = 0;
    }
    return *this;
  }

  int get_m() const { return m; }
};

int main (int argc, char *argv[]) {

  std::vector<IntContainer> v{10}; <- (n)
  IntContainer obj(12); <- (m)
  std::fill(v.begin(), v.end(), obj); <- (first, last, value_)
  for(auto var : v) => IntContainer
  {
    // `m` is 12 only for the first element here and rest have value zero
    std::cout << var.get_m() << std::endl;
  }
  return 0;
}

Recommended

#include <iostream>
#include <algorithm>
#include <vector>

class IntContainer {
  int m;

public:
  IntContainer() : m(0) {}
  explicit IntContainer(int m) : m(m) {}

  IntContainer& operator=(const IntContainer &other) {
    if (&other != this) {
      m = other.m;
    }
    return *this;
  }

  int get_m() const { return m; }
};

int main (int argc, char *argv[]) {

  std::vector<IntContainer> v{10}; <- (n)
  IntContainer obj(12); <- (m)
  std::fill(v.begin(), v.end(), obj); <- (first, last, value_)
  for(auto var : v) => IntContainer
  {
    std::cout << var.get_m() << std::endl;
  }
  return 0;
}

References