コピーコンストラクタを無効にする


173

私はクラスを持っています:

class SymbolIndexer {
protected:
  SymbolIndexer ( ) { }

public:
  static inline SymbolIndexer & GetUniqueInstance ( ) 
  { 
    static SymbolIndexer uniqueinstance_ ;
    return uniqueinstance_ ; 
  }
};

次のようなコードを無効にするにはどうすればよいですか?

SymbolIndexer symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );

次のようなコードのみを許可します:

SymbolIndexer & ref_symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );

1
ところで、これは継承のための規定がある(保護されている)シングルトンですか?
R.マルティーニョフェルナンデス

私はあなたのコードに疑問があります。異なるインスタンスが作成されるたびに、GetUniqueInstance()は常に同じオブジェクトへの参照を与えると思います。
Pratham Shah

回答:


286

コピーコンストラクターをプライベートにして、実装を提供しないことができます。

private:
    SymbolIndexer(const SymbolIndexer&);

またはC ++ 11では、明示的に禁止します。

SymbolIndexer(const SymbolIndexer&) = delete;

43
deleteキーワードに関しては以下を追加したいと思います。新しいクラスを設計するときの私の現在の習慣はdelete、コピーコンストラクターと代入演算子の両方をすぐに使用することです。状況によっては、ほとんど不要であり、それらを削除することで、予期しない動作のいくつかのケースを防ぐことができます。コピートラクターが必要になる可能性がある状況が発生した場合は、移動セマンティクスでそれが可能かどうかを判断します。これが望ましくない場合は、コピートラクターと代入演算子の両方に実装を提供してください(!)。これが良いアプローチであるかどうかは、読者にまかせます。
pauluss86 2014

1
@ pauluss86私はあなたのアプローチが好きですが、このパターンを実行するのに費やした時間は、それが防止するエラーによって節約された時間よりも大きいと思うので、私は完全にコミットしません。よくわからないときは、コピーを禁じます。
トマーシュZato -復活モニカ

@ pauluss86これは基本的にRustが行うことです:Move-by-default(およびconst-by-default)。私の意見では非常に役に立ちます。
カピチュ16

33

多重継承を気にしない場合(結局のところ、それほど悪くはありません)、プライベートコピーコンストラクターと代入演算子を使用して単純なクラスを記述し、さらにサブクラス化することができます。

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

class SymbolIndexer: public Indexer, public NonAssignable {
};

GCCの場合、次のエラーメッセージが表示されます。

test.h: In copy constructor ‘SymbolIndexer::SymbolIndexer(const SymbolIndexer&)’:
test.h: error: ‘NonAssignable::NonAssignable(const NonAssignable&)’ is private

ただし、これがすべてのコンパイラで機能するかどうかはよくわかりません。関連する質問がありますが、まだ回答はありません。

UPD:

C ++ 11ではNonAssignable、次のようにクラスを記述することもできます。

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

delete彼らは、派生クラスの既定で構築メンバーにさらに使用することはできませんのでからキーワード防止のメンバーは、デフォルトで構築されています。割り当てようとすると、GCCで次のエラーが発生します。

test.cpp: error: use of deleted function
          ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
test.cpp: note: ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
          is implicitly deleted because the default definition would
          be ill-formed:

UPD:

Boostには、同じ目的のためのクラスが既にありますが、同じように実装されていると思います。クラスが呼び出さboost::noncopyableれ、次のように使用されることを意図しています:

#include <boost/core/noncopyable.hpp>

class SymbolIndexer: public Indexer, private boost::noncopyable {
};

プロジェクトポリシーで許可されている場合は、Boostのソリューションを使用することをお勧めします。詳細については、boost::noncopyable関連する別の質問も参照してください。


それでいいのNonAssignable(const NonAssignable &other);
Troyseph 2015年

この質問は、C ++ 11 deleteキーワード構文に更新された場合、さらに多くの賛成票を獲得できると思います。
トマーシュZato -復活モニカ

@TomášZato:アイデアは、コピーコンストラクターと代入演算子を存在させるが、非公開にすることです。あなたがdelete彼らなら、それは機能しなくなります(私はチェックしたところです)。
firegurafiku 2016年

@TomášZato:ああ、申し訳ありませんが、私のテスト方法は少し間違っていました。削除も機能します。すぐに答えを更新します。
firegurafiku 2016年

3
@Troyseph:const Class&Class const&ほとんど同じです。ポインタの場合は、Class const * constタイプすることもできます。
firegurafiku 2016年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.