2009-09-21 8 views
31

クラスのコピーや割り当てを禁止するには、コピーコンストラクタ と代入演算子をprivateにするのが一般的です。 GoogleとQtの両方に、これを簡単に見えるようにするマクロがあります。 これらのマクロは、以下のとおりです。クラスのコピーと割り当てを禁止するマクロ。 Google -vs-Qt

グーグル:

#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ 
    TypeName(const TypeName&); \ 
    void operator=(const TypeName&) 

のQt:

#define Q_DISABLE_COPY(Class) \ 
    Class(const Class &); \  
    Class &operator=(const Class &); 

質問: なぜ2つの代入演算子の署名が異なっていますか? Qtのバージョンが正しいようです。 両者の実際の違いは何ですか?

+2

もう一つの小さな違いは、Qtの適応がセミコロンで終わることです。 – Dennis

答えて

5

実際的な違いはありません。代入演算子のシグネチャは、スタイルの問題と同様に異なります。代入演算子に連鎖を許可するための参照を返すのは普通です:

a = b = c;

しかし、voidを返すバージョンも有効です。唯一の目的は、オペレータprivateを宣言して使用することを唯一の目的としている場合にうまく機能します。あなたはこの1つを書くたら

1

はどちらも同じ目的

を果たす:

Class &operator=(const Class &); 

あなたがチェーンの割り当ての利点を取得します。しかし、この場合、代入演算子をプライベートにする必要があります。それは問題ではありません。

41

問題ではありません。戻り値の型は、関数のシグネチャの一部ではありません。オーバーロード解決に関与しないためです。したがって、代入を実行しようとすると、戻り値の型を使用するかどうかにかかわらず、両方の宣言が一致します。

これらのマクロ内のすべての点は、関数が決して呼び出されないため、voidを返しても問題ありません。

+0

それは私が思った...ありがとう。 Googleのバージョンは、あなたが通常見ているものではないので、ちょっと珍しいことでした。 – RobertL

2

他の人は、operator =に異なる戻り値を持つことが合理的である理由は既に答えています。 IMHO jalf said it best

しかし、 Googleは異なる戻り値の型を使用していますなぜあなたはを疑問に思うかもしれません、と私はそれがこのだ疑い:

あなたはこのような代入演算子を無効にする場合型名を繰り返す必要はありません。通常、型名は宣言の最長部分です。

もちろん、マクロは使用されていますが、まだまだ古い習慣は枯渇しています。 :-)

1

Qtバージョンは下位互換性がありますが、Googleではありません。

ライブラリを開発し、完全に削除する前にライブラリの使用を非難する場合は、Qtで元々持っていた署名を保持する可能性が高くなります。この場合、古いアプリケーションは新しいバージョンのライブラリで引き続き実行されます(ただし、は新しいバージョンでをコンパイルしません)。

Googleのマクロには、このようなプロパティはありません。

9

Boost.Utility、特にboost::noncopyableを参照してください。これはマクロではなく、プライベートコピーと割り当てを持つ基本クラスです。コンパイラが派生クラスで暗黙のコピーと割り当てを生成しないようにします。

編集:申し訳ありませんが、これは元の質問に対する回答ではありませんでした。ところで、boost :: noncopyableは代入演算子の戻り値の型としてconst参照を使います。戻り値の型は使用されていないので重要ではないという印象を受けました。それでも、演算子を非公開にしても、クラスや友人の内部での使用が妨げられることはありません。その場合、通常の戻り値の型(void、const参照など)はコンパイルエラーにつながり、追加のバグを引き起こす可能性があります。

15

私は、クラスのコピーと割り当てを禁止するための抽象化を実装するための代替戦略があることを言いたいと思います。考え方は、プリプロセッサの代わりに継承を使うことです。私は個人的には、可能な限りプリプロセッサの使用を避けるのが最善であるという経験則に従って、このアプローチを好む。

boost::noncopyableは実装例です。

class A : noncopyable 
{ 
    ... 
}; 
+0

+1私がこのように理解しているように、コンパイラエラーは常に発生しますが、同じクラスで非公開宣言するとリンカーエラー(実装されていない)が発生する場合があります。 – UncleBens

+3

それらを非公開と宣言するとコンパイラエラー – RobertL

+0

@RobertLが返されますが、あなたはまだ 'struct X {NON_COPYABLE(X); void f(){X x、y(x); }}; 'リンク時にのみエラーが発生します。コピー不可能なものから継承することもそれを許さないでしょう。 –

0

をところであなたはBoostライブラリへのアクセス権を持っている場合は、ユーティリティライブラリが長時間noncopyable classてきました(あなたがいないのはなぜ一体ではない???)、::これは次のように使用されている

class YourNonCopyableClass : boost::noncopyable { 

もっと明確なIMHO。規格から

4

、12.8、条項9:「ユーザー宣言コピー代入演算子X::operator=タイプXのうちの正確に1つのパラメータ、X&、CONST X&持つクラスXの非静的非テンプレートメンバー関数であり、揮発性X& 、またはconst volatile X& "戻り値の型については何も言わないので、戻り値の型は許可されています。

第10項では、「クラス定義が明示的にコピー代入演算子を宣言していない場合、暗黙的に宣言されています。

したがって、X::operator=(const X&)(または指定された割り当てタイプのいずれか)を宣言するだけで十分です。オペレーターが決して使用されないなら、ボディーもリターンタイプも重要ではありません。

したがって、1つのマクロが期待していることを行い、1つは少数のキャラクターを保存して、一部の人を驚かせるような方法で仕事をすることで、文体の違いになります。私はQtマクロが書式的に優れていると思います。私たちはマクロを話しているので、プログラマーが余分なものを入力しなければならないという話ではなく、人々を驚かせることができないということは、言語構造の中では良いことです。

1

関数の戻り値の型は関数のシグニチャには含まれないため、クラスのクライアントが代入演算子を使用できなくなるまで、両方の宣言は同等です。

個人的に私はクラスを非公開で空の非コピー可能な基本クラス(boost :: noncopyableのように継承していますが、私は自分自身で持っていますので、ブーストを利用できないプロジェクトで使用できます) 。空の基底クラスの最適化は、オーバーヘッドがゼロであることを確認します。シンプルで読みやすく、恐ろしいプリプロセッサマクロの機能に依存しません。

また、クラスの実装コード内でコピーと割り当てを使用することもできないという利点があります。これらのマクロはリンク時に失敗する(コンパイル時にはエラーメッセージが表示されません)。

関連する問題