本文へスキップ
BecomeCoder

C++コース · 第12章 演算子オーバーロードとコピー/ムーブ · レッスン52

Rule of Five / Rule of Zero

ブラウザで完結

導入

ここまでで「デストラクタ・コピー・ムーブ」という特別なメンバ関数が出そろいました。これらは互いに関係しあうため、「どれかを書くなら、まとめて考える」という指針があります。それが Rule of Five と Rule of Zero です。

説明

資源を手で管理するクラスでは、次の5つを一組で考えます(Rule of Five)。1つでも自前で書くなら、残りも検討すべき、という経験則です。

flowchart TB
  subgraph FIVE["Rule of Five(5つの特別メンバ)"]
    a["デストラクタ ~T()"]
    b["コピーコンストラクタ T(const T&)"]
    c["コピー代入 operator=(const T&)"]
    d["ムーブコンストラクタ T(T&&)"]
    e["ムーブ代入 operator=(T&&)"]
  end

しかし現代の C++ で本当に推奨されるのは、その逆の Rule of Zero です。資源管理を std::vectorstd::string、スマートポインタ(第16章)といった「自分で片付けてくれる部品」に任せれば、5つとも自分で書く必要がなくなります。

#include <iostream>
#include <vector>
#include <string>
using namespace std;

// Rule of Zero:資源は vector / string に任せる
// → デストラクタもコピーもムーブも自分で書かなくて正しく動く
class Player {
    string name;
    vector<int> scores;
public:
    Player(string n) : name(n) {}
    void addScore(int s) { scores.push_back(s); }
    int total() const {
        int t = 0;
        for (int s : scores) t += s;
        return t;
    }
};

int main() {
    Player p("たろう");
    p.addScore(80);
    p.addScore(95);

    Player q = p;    // コピーも自動で正しく動く(vector が深いコピーしてくれる)
    q.addScore(100);
    cout << p.total() << " " << q.total() << endl;  // 175 275(独立)
    return 0;
}

まとめ

資源を手で持つなら5つの特別メンバを一組で考える(Rule of Five)。しかし現代の C++ では、資源管理を標準の部品に委ね、5つとも書かずに済ませる Rule of Zero が最善です。「生ポインタを直接持たない」ことが、安全なクラス設計の近道です。

実際に動かしてみよう

下のエディタにC++を書いて「コンパイル & 実行」を押すと、ブラウザ内で本物のC++コンパイラ(clang + libc++)がその場でコンパイルして実行し、出力が表示されます。std::string・vector・クラス・テンプレート・STL などモダンC++がそのまま動きます。本文の例を書き換えて試しながら進めましょう(初回だけコンパイラの読み込みに時間がかかります。以降はキャッシュされます。この回は標準入力(cin)は使わず、値はコードに直接書きます)。

C/C++ — ブラウザ内で本物のコンパイラで実行

ブラウザ内で本物のC/C++コンパイラ(clang + libc++ / WebAssembly)を動かします。構造体・malloc/free・std::string・vector・クラス・テンプレート・STL などがそのまま実行できます(初回のみコンパイラの読み込みに時間がかかります。以降はブラウザにキャッシュされます)。
スクロールして表示された時点でも自動で読み込まれます。