# はじめに
Effective C++ 第3版の6項31ページから勉強していきます。
今回は、「コンパイラによるコピーコンストラクタの自動生成の禁止」についです。
Effective C++ 第3版 - 6項 コンパイラが自動生成することを望まない関数は使用を禁止しよう -
コンパイラによるコピーコンストラクタの自動生成の禁止
コンパイラによるコピーコンストラクタの自動生成の禁止
前回の投稿で、クラス内で、コピーコンストラクタ、コピー代入演算子、デストラクタを宣言しなければ、コンパイラが自動でそれらを生成すると書きました。
しかし、コピーコンストラクタ、コピー代入演算子を使用することが望ましくない場合でも、自動で生成してしまいます。
以下に例を示します。
例のように、HomeForSaleオブジェクトをコピーするようなコードがあれば、コンパイルできないようにしたいと思います。
class HomeForSale {
public:
explicit HomeForSale(const std::string &city, const int &value) {
city_ = city;
value_ = value;
}
private:
std::string city_;
int value_;
};
HomeForSale h1("Tokyo", 2);
HomeForSale h2("Osaka", 3);
HomeForSale h3(h1); // h1をコピーコンストラクタでコピーしようとしている
// これをコンパイルできないようにしたい
h1 = h2; // h2を代入によってコピーしようとしている
// これをコンパイルできないようにしたい
しかし、このコードをコンパイルを禁止する簡単な方法はありません。
普通に、クラスに特定の関数を使用したくない場合、その関数を宣言しなければ良い。
しかし、コピーコンストラクタ・コピー代入演算子は、上で言ったように、コンパイラが自動で生成してしまいます。
一方、コピーコンストラクタ・コピー代入演算子を宣言してしまうと、やはりコピーをサポートすることになってしまいます。
この問題は、「コンパイラが生成する関数は、すべてpublic」というのが原因です。
コピーコンストラクタ・コピー代入演算子の自動生成を避けるためには、プログラマ自身が宣言するしかないのです。
ただし、publicではなく、privateに宣言します。
これらの関数を明示的に宣言することで、コンパイラによる自動生成を防ぐことができる。
さらに、それらがprivateに宣言されているのであれば、それらを外部から利用することはできなくなります。
しかし、他のメンバ関数はprivateな関数を呼び出すことできるので、
コピーコンストラクタ・コピー代入演算子の宣言だけし、定義を書かないことで、メンバ関数からの呼び出しを防ぐ。
そのため、下のようになります。
class HomeForSale {
public:
explicit HomeForSale(const std::string &city, const int &value) {
city_ = city;
value_ = value;
}
private:
std::string city_;
int value_;
HomeForSale(const HomeForSale&); // 追加
HomeForSale &operator=(const HomeForSale &); // 追加
};
HomeForSale h1("Tokyo", 2);
HomeForSale h2("Osaka", 3);
HomeForSale h3(h1); // コンパイルエラー
h1 = h2; // コンパイルエラー
以下に、勉強で使用したコードを示します。
サンプルコード
#include <iostream>
/*
Effective C++ 6項
コンパイラが自動生成するコピーコンストラクタを生成しないようにする方法
*/
class HomeForSale {
public:
explicit HomeForSale(const std::string &city, const int &value) {
city_ = city;
value_ = value;
}
private:
std::string city_;
int value_;
HomeForSale(const HomeForSale&);
HomeForSale &operator=(const HomeForSale &);
};
int main(int argc, char *argv[]) {
std::cout << "6_no_copy_constract.cpp" << std::endl;
HomeForSale h1("Tokyo", 2);
HomeForSale h2("Osaka", 3);
HomeForSale h3(h1); // h1をコピーコンストラクタでコピーしようとしている
// これをコンパイルできないようにしたい
h1 = h2; // h2を代入によってコピーしようとしている
// これをコンパイルできないようにしたい
}
実行結果
参考文献
[1] https://www.amazon.co.jp/gp/product/4621066099/ref=dbs_a_def_rwt_hsch_vapi_taft_p1_i0