C++の特殊メンバー関数

編集

概要

編集

特殊メンバー関数は、C++クラスのオブジェクトライフサイクルを制御する特別な関数群です。以下の6つの関数が含まれます:

  1. デフォルトコンストラクタ
  2. デストラクタ
  3. コピーコンストラクタ
  4. コピー代入演算子
  5. ムーブコンストラクタ (C++11)
  6. ムーブ代入演算子 (C++11)

Rule of Zero/Three/Five

編集

Rule of Zero

編集

現代のC++では、可能な限り「Rule of Zero」に従うことが推奨されます。これは、特殊メンバー関数を明示的に定義せず、標準ライブラリのRAIIコンテナを使用してリソース管理を行う方針です。

class User {
    std::string name_;
    std::vector<int> data_;
public:
    // 特殊メンバー関数は一切定義しない
    // →コンパイラが適切な実装を生成
};

Rule of Three

編集

リソースを直接管理する必要がある場合は、以下の3つを必ず定義します:

  1. デストラクタ
  2. コピーコンストラクタ
  3. コピー代入演算子
class ResourceHandler {
    int* data_;
public:
    ~ResourceHandler() { delete data_; }
    ResourceHandler(const ResourceHandler& other) : data_(new int(*other.data_)) {}
    ResourceHandler& operator=(const ResourceHandler& other) {
        if (this != &other) {
            auto* tmp = new int(*other.data_);
            delete data_;
            data_ = tmp;
        }
        return *this;
    }
};

Rule of Five (C++11以降)

編集

C++11以降では、ムーブセマンティクスをサポートするために、以下の5つを定義します:

  1. デストラクタ
  2. コピーコンストラクタ
  3. コピー代入演算子
  4. ムーブコンストラクタ
  5. ムーブ代入演算子
class ModernResourceHandler {
    std::unique_ptr<int> data_;
public:
    // デストラクタはunique_ptrが処理
    ~ModernResourceHandler() = default;
    
    // コピー操作
    ModernResourceHandler(const ModernResourceHandler& other)
        : data_(other.data_ ? new int(*other.data_) : nullptr) {}
    
    ModernResourceHandler& operator=(const ModernResourceHandler& other) {
        if (this != &other) {
            data_.reset(other.data_ ? new int(*other.data_) : nullptr);
        }
        return *this;
    }
    
    // ムーブ操作
    ModernResourceHandler(ModernResourceHandler&&) noexcept = default;
    ModernResourceHandler& operator=(ModernResourceHandler&&) noexcept = default;
};

特殊メンバー関数の制御

編集

=default と =delete

編集

C++11以降では、特殊メンバー関数の生成を明示的に制御できます:

class ControlledClass {
public:
    // デフォルト実装を使用
    ControlledClass() = default;
    
    // コピーを禁止
    ControlledClass(const ControlledClass&) = delete;
    ControlledClass& operator=(const ControlledClass&) = delete;
    
    // ムーブを許可
    ControlledClass(ControlledClass&&) noexcept = default;
    ControlledClass& operator=(ControlledClass&&) noexcept = default;
};

暗黙の定義規則

編集

特殊メンバー関数の暗黙の定義には以下のルールがあります:

  • デストラクタを定義すると、ムーブ操作は暗黙的に削除される
  • コピー操作を定義すると、ムーブ操作は暗黙的に削除される
  • ムーブ操作を定義すると、コピー操作は暗黙的に削除される

モダンC++におけるベストプラクティス

編集

スマートポインタの活用

編集

生ポインタの代わりにスマートポインタを使用することで、リソース管理を安全に行えます:

class ModernClass {
    std::unique_ptr<Resource> resource_;
    std::shared_ptr<SharedData> shared_data_;
public:
    // unique_ptrとshared_ptrが特殊メンバー関数を適切に処理
};

noexcept の適切な使用

編集

ムーブ操作では、可能な限り noexcept を指定します:

class NoexceptMoves {
public:
    NoexceptMoves(NoexceptMoves&& other) noexcept = default;
    NoexceptMoves& operator=(NoexceptMoves&& other) noexcept = default;
};

例外安全性の確保

編集

特殊メンバー関数では、強い例外保証を提供することが重要です:

class ExceptionSafe {
    std::unique_ptr<Resource> resource_;
public:
    ExceptionSafe& operator=(const ExceptionSafe& other) {
        // コピー後スワップイディオム
        auto temp = std::make_unique<Resource>(*other.resource_);
        resource_.swap(temp);
        return *this;
    }
};

まとめ

編集

現代のC++における特殊メンバー関数の指針

編集
  1. 可能な限りRule of Zeroに従う
  2. 直接リソース管理が必要な場合はRule of Threeまたは Rule of Fiveに従う
  3. スマートポインタとRAIIを活用する
  4. ムーブ操作にはnoexceptを指定
  5. 例外安全性を確保する

これらの原則に従うことで、安全で効率的なクラス設計が可能になります。