CERT.OOP.COPY_MUTATES

コピー操作により、ソースオブジェクトが変異してはなりません。

脆弱性とリスク

コピー操作 (コピーコンストラクタとコピー代入演算子) では、ソースオブジェクトの最も重要なプロパティを宛先オブジェクトにコピーし、オリジナルの「コピー」であるオブジェクトを生成する必要があります。型のどのプロパティが重要であるかは型によって異なります。比較演算子や等価演算子をエクスポーズする型の場合、それらの比較操作に使用されるプロパティなどが重要です。こうした予期からは、コピー操作によってソースオブジェクトの値表現と同等の値表現を持つ宛先オブジェクトを生成するという、コードにおける前提が生じます。この基本的な前提に違反すると、予期しない動作が発生する可能性があります。

軽減と防止

コピー演算子を実装するときには、外部から識別できる、ソースオブジェクトオペランドのメンバーや、グローバルにアクセス可能な情報を変異させてはなりません。外部から識別できるメンバーには、比較操作や等価操作に関わるメンバーや、パブリック API を介して値がエクスポーズされるメンバー、グローバル変数などがあります (これらに限定はされません)。

コピー
  #include <algorithm>
  #include <vector>
  
  class A {
    mutable int m;
  
  public
    A() : m(0) {}
    explicit A(int m) : m(m) {}
 
   A(const A &other) : m(other.m) {
     other.m = 0;               //uncompliant code
   }
 
   A& operator=(const A &other) {
     if (&other != this) {
       m = other.m;
       other.m = 0;              //uncompliant code
     }
     return *this;
   }
 
   int get_m() const { return m; }
 };
 
 void f() {
   std::vector<A> v{10};
   A obj(12);
   std::fill(v.begin(), v.end(), obj);
 }