59

C++11 で明示的に削除されたメンバー関数を使用して、コピー不可能な基本クラスから継承する価値はありますか?

私は、プライベートまたは削除されたコピーコンストラクターとコピー割り当てを持つ基本クラスをプライベートに継承するトリックについて話している (例: boost::noncopyable)。

この質問で提示された利点は、C++11 にも適用できますか?


C++11 でクラスをコピー不可にする方が簡単だと主張する人がいる理由がわかりません。

C++03 の場合:

private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}

C++11 の場合:

MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;

編集:

多くの人が指摘しているように、プライベート コピー コンストラクターとコピー代入演算子に空のボディ (つまり {}) を提供するのは間違いでした。最初は {} を追加しないことから始めましたが、リンカーの問題に遭遇し、ばかげた理由で {} を追加しました (状況を覚えていません)。私はよく知っている。:-)

4

5 に答える 5

76

さて、これ:

private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}

MyClass技術的には、メンバーや友人がコピーすることはまだ許可されています. 確かに、これらの型と関数は理論的にはユーザーが制御できますが、クラスはまだcopyableです。少なくともboost::noncopyable= deleteでは、誰もクラスをコピーできません。


C++11 でクラスをコピー不可にする方が簡単だと主張する人がいる理由がわかりません。

「消化しやすい」ほど「簡単」ではありません。

このことを考慮:

class MyClass
{
private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}
};

あなたが C++ の入門テキストを読んだことがあるが、慣用的な C++ にほとんど触れていない C++ プログラマー (つまり、多くの C++ プログラマー) である場合、これは... 混乱を招きます。コピー コンストラクターとコピー代入演算子を宣言しますが、それらは空です。では、なぜそれらを宣言するのでしょうか。はい、それらは ですprivate。しかし、それだけではさらに疑問が生じます。なぜそれらを非公開にするのですか?

これがコピーを妨げる理由を理解するには、それらを非公開と宣言することで、非メンバー/友人がコピーできないようにすることを理解する必要があります. これは、初心者にはすぐにはわかりません。また、コピーしようとしたときに表示されるエラー メッセージもありません。

次に、C++11 バージョンと比較します。

class MyClass
{
public:
    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass&) = delete;
};

このクラスがコピーできないことを理解するには何が必要ですか? = delete構文の意味を理解することに他なりません。C++11 の構文規則を説明している本は、それが何をするかを正確に教えてくれます。このコードの効果は、経験の浅い C++ ユーザーには明らかです。

この慣用句の優れている点は、言いたいことを正確に伝える最も明確で明白な方法であるため、慣用句になることです。

もう少しboost::noncopyable考える必要があります。はい、それは「コピー不可」と呼ばれているため、自己文書化されています。しかし、これまでに見たことがない場合は、疑問が生じます。なぜコピーできないものから派生しているのですか?boost::noncopyableエラー メッセージがのコピー コンストラクターについて言及しているのはなぜですか? 繰り返しますが、慣用句を理解するには、より多くの精神的な努力が必要です。

于 2012-02-27T01:05:00.490 に答える
24

最初のことは、私の前に他の人が指摘しているように、あなたはイディオムを間違っており、プライベートとして宣言し、定義していないということです:

class noncopyable {
   noncopyable( noncopyable const & );
   noncopyable& operator=( noncopyable const & );
};

の戻り値の型はoperator=基本的に何でもかまいません。この時点で、ヘッダーでそのコードを読むと、実際にはどういう意味になるでしょうか? 友達だけがコピーできますか、それともコピーできませんか? あなたの例のように定義を提供する場合、それは私がクラス内でのみコピーでき、友人によってコピーできると述べていることに注意しください。ただし、ヘッダーに定義がないことは、どこにでも定義がないことと同義ではありません。cpp ファイルで定義できるからです。

これは、noncopyableと呼ばれる型から継承することで、意図がコピーを回避することであることが明示される場所です。これは、上記のコードを手動で記述した場合、意図がコピーを無効にする行にコメントを付けて文書化する必要があるのと同じ方法です。

C++11 はこれを変更しません。コード内でドキュメントを明示的にするだけです。コピー コンストラクターを削除済みとして宣言する同じ行で、完全に無効にすることが文書化されています。

最後のコメントとして、C++11 の機能は、より少ないコードまたはより優れたコードでコピー不可を記述できるようにすることだけではなく、生成したくないコードをコンパイラが生成するのを禁止することでもあります。これは、その機能の使用方法の 1 つにすぎません。

于 2012-02-27T01:26:19.027 に答える
10

他の人が提起したポイントに加えて...

定義していないプライベートコピーコンストラクターとコピー代入演算子があると、だれもコピーを作成できなくなります。ただし、メンバー関数またはフレンド関数がコピーを作成しようとすると、リンク時エラーが発生します。これらの関数を明示的に削除した場所でそうしようとすると、コンパイル時エラーが発生します。

私は常にエラーをできるだけ早く発生させます。実行時エラーが後でではなくエラーの時点で発生するようにします(したがって、変数を読み取るときではなく、変数を変更したときにエラーが発生するようにします)。すべての実行時エラーをリンク時エラーにして、コードが間違っている可能性がないようにします。すべてのリンク時エラーをコンパイル時エラーにして、開発をスピードアップし、少し便利なエラーメッセージを表示します。

于 2012-08-13T01:00:39.200 に答える
5

より読みやすく、コンパイラがより良いエラーを出すことができます。

「削除された」ことは、特にクラスをざっと読んでいる場合、読者にとってより明確です。同様に、コンパイラは、一般的な「プライベート メンバーにアクセスしようとしています」というエラーを表示する代わりに、コピーできない型をコピーしようとしていることを通知できます。

しかし、実際には、それは単なる便利な機能です。

于 2012-02-27T00:53:18.480 に答える
2

ここの人々は、メンバー関数を定義せずに宣言することを推奨しています。このようなアプローチは移植可能ではないことを指摘したいと思います。一部のコンパイラ/リンカーでは、メンバー関数を宣言する場合は、それが使用されていない場合でも定義する必要があります。VC++、GCC、clang のみを使用している場合はこれで問題ありませんが、真に移植可能なコードを書こうとしている場合は、他のコンパイラ (Green Hills など) は失敗します。

于 2014-01-07T23:04:10.233 に答える