class を noncopyable にする

今時のc++ (c++11など)でコピー禁止,代入禁止のクラスを作る方法

template <class T>
struct CRTPnoncopyable {
    CRTPnoncopyable(const CRTPnoncopyable&) = delete;
    CRTPnoncopyable& operator=(const CRTPnoncopyable &) = delete;
};

class A : CRTPnoncopyable<A> {};

これでclass Aはコピー禁止になる*1 *2

Boost の noncopyable を使う方法もある *3

#include <boost/core/noncopyable.hpp>

class A : boost::noncopyable {};


両者の違いは何か.


それはクラスを継承した際に現れる.

#include <iostream>
#include <boost/core/noncopyable.hpp>

template <class T>
struct CRTPnoncopyable {
    CRTPnoncopyable(const CRTPnoncopyable&) = delete;
    CRTPnoncopyable& operator=(const CRTPnoncopyable &) = delete;
};

class A1 : boost::noncopyable {};
class A2 : boost::noncopyable {};
class AA: A1, A2 {};

class C1 : CRTPnoncopyable<C1> {};
class C2 : CRTPnoncopyable<C2> {};
class CC : C1, C2 {};

int main()
{
    std::cout << "sizeof(AA) = " << sizeof(AA) << std::endl;
    std::cout << "sizeof(CC) = " << sizeof(CC) << std::endl;
    return 0;
}

class AAがboost版,class CC がテンプレート版であり,これを実行すると

sizeof(AA) = 2
sizeof(CC) = 1

となる.つまり class CC の方がコンパクトになっている

これはboost版では,コンパイラが Empty Base Optimization を適応できないためである.詳細は以下のページが詳しい
https://ja.wikibooks.org/wiki/More_C%2B%2B_Idioms/%E3%82%B3%E3%83%94%E3%83%BC%E7%A6%81%E6%AD%A2%E3%83%9F%E3%83%83%E3%82%AF%E3%82%B9%E3%82%A4%E3%83%B3%28Non-copyable_Mixin%29


実際に使うときはマクロを使うと便利 (2022年8月15日更新)

// マクロの定義
#define NONCOPYABLE(ClassName) ClassName(const ClassName&)=delete; ClassName& operator=(const ClassName&)=delete


// 使い方
class MyClass {
    NONCOPYABLE(MyClass);
};



*1:旧来のc++と異なり,c++0xで default, delete が登場したので簡潔にかける

*2:CRTPとはCuriously Recurring Template Patternの略で class A : hogehoge<A> の形,つまりAの基底クラスが Aで特殊化されたテンプレートクラスであるパターンを意味する

*3:以前は boost::noncopyable は boot/utility.hpp にて定義されていたが,いつの間にか boost/core/に昇格されている