2009-08-27 21 views
16

当社のコーディング標準では、「(偶発的な)コピーを防止できる方法に注意してください」と言われています。は、偶発的なオブジェクトのコピーをC++で防止します

私はこのことがどういう意味なのかよく分かりませんが、必要でない場合は、クラスのコピーを停止する必要があると仮定します。

次のように私は考えることができることである。

  1. はプライベートクラスのコピーコンストラクタを作成します。
  2. クラスの代入演算子(operator =)をprivateにします。
  3. クラスのコンストラクタを明示的にします(不正な変数を使用してクラスを作成しないようにします)。
  4. メモリの割り当てを行い、コピーが必要なすべてのクラスで、コピーコンストラクタと代入演算子が浅いコピーではなくディープコピーを実行することを確認します。

正しい軌道に乗っていますか?私が逃したかもしれないものはありますか?

+0

+1。私はあなたがそこにあなたのリストに正確にあると思う:) – kkaploon

+0

実際には、私はあなたがこれらのことを知っているべきであり、あなたが間違ってあなたが想定していないオブジェクトをコピーしていないことを知っていることを意味する文章を理解していただろう。しかし、私は何を知っていますか?とにかく、この方法はもっと面白いです。 –

答えて

9

あなたのコーディング標準では「(偶然の)コピーを防ぐことができる」ことを認識しているならば、クラス内からのコピーを防ぐことだけではなく、不要な/ クラスを使用すると、/偶発的なコピー。

C++の新しいコードで不必要に浪費されるパフォーマンスの主な原因の1つは、通常は一時的な方法による不要なコピーです。一時的なものが必要ないときは、コンパイラが良くなってきています("Want speed? Pass by Value"、Konradのコメントのおかげで)が、C++でのコピーや一時的な処理の中身を知ることを学ぶことが最善の方法です。私のために、Efficient C++を読んで本当に私を始めました。

+2

コピーエリートとNRVOを考慮すると、2番目の点は大きく誤った/誤解を招きます。プロフェッショナルの話を聞かせるには:http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ –

+0

これは本当に素晴らしい記事です - 私はRVOを知っていましたが、最後に掘り下げたときそれを深く私はまだVS2003を使用していた、それはより複雑なタイプのためにそれを得るためにコンパイラに依存することは危険なビジネスでした。 C++の問題ではなくなっていると聞いてうれしい0X –

+0

@MadKeithV:この記事のC++ 0x:* everything *は、現在のコンパイラと現在のバージョンに当てはまりますC++では、C++ 0xの新機能はありません。 –

10

あなたはブーストを使用している場合は、コピーされるクラスを防止するための最も簡単な方法は、noncopyableからクラスを派生させている。

#include <boost/noncopyable.hpp> 

class Foo : private boost::noncopyable 
{ 
} 

これは、手動でコピーコンストラクタとassigmentオペレータを作るよりも、あなたの意図が明確になります非公開で、同じ結果が得られます。

+0

クラスをコピーしないようにしたいとは思っていませんでしたが、誤ってコピーされることを避けたいと思っています。 – kkaploon

+0

コピーコンストラクタを非公開にするオプションの1つとしてリストされているので、私は彼がそう信じています。 –

+0

私はブーストが好きですが、私は単純に許可されていない多くの作業状況に挑戦しました。 – Greg

21

はい、代入演算子とコピーコンストラクタをprivateにすると、standartメソッドを使用してオブジェクトのコピーを作成できなくなります(実際にオブジェクトのコピーが必要な場合は、たとえばCopy()メソッドを実装できます)。深いコピーを実行する)。

boost::noncopyableをご覧ください。 (タルプレスマンへの再)

更新

...あなたはこれらの事を認識し、あなたが誤ってあなたがになっていないオブジェクトをコピーしないことに注意すべきです。

まあ、私はどの偶発コピーが代入演算子やコピーコンストラクタのいずれかを使用して実行されることを、推測します。オブジェクトのコピーがコストのかかる操作である場合、コピーは明示的でなければなりません。他の開発者が意図せず間接的にcopy opを呼び出す可能性があり、コンパイラはこれが禁止されていることを通知します。

+0

ブーストコピー不可の場合 –

2

あなたは正しい方向にあります。ブーストを使用したくない場合は、次のことを行うことができます。コピーコンストラクタを作成し、代入演算子をプライベートにコピーし、それらを実装しません。したがって、インスタンスをコピーしようとするとコンパイラエラーが発生します。

0

あなたのリストは、エラーを避けるという観点から見えます。暗黙のオブジェクトのコピーからの共有ポインタのために同じメモリ領域を2回以上削除します。

これもまた適切です。 「偶発的なコピーが防止できる方法を認識している」という声明から、「意図しない不要なコピーを認識している」ことを意味すると思われるかもしれません。これは、パフォーマンスに影響する可能性のある状況を意味します。非常に単純な例では、あなたのコーディング規則は、あなたが好むはずです意味するかもしれない:

std::string text1("some text"); 

オーバー:

std::string text1 = "some text"; 

後者の場合は、割り当ての前に、「テキスト」を保持するために作成された一時的な文字列につながります演算子が呼び出され(コピーの形式)、text1に「何らかのテキスト」が設定されます。明らかにこれは簡単な例であり、可能な限りコンストラクタの初期化(最初の例)を使用するように指示するのがよい習慣です。

+0

ご意見ありがとうございます。これは私が知らないことです。型変換が必要な場合は、代入を使用するのではなく、常にコンストラクタを呼び出します。 – Andy

+0

私はあなたがこれで正しいと確信していません。 両方とも一時的なchar []を作成します。 –

+1

いいえ、それは間違っています。 *すべての現代のコンパイラはこの場合、 'std :: string'の不要な一時インスタンスを避けます。 –

0

はい、あなたは欠けていることがあります。メンバー関数があるオブジェクトを別のオブジェクトにコピーしているクラスにケースがある可能性があります。 メンバー関数は、プライベートコピーコンストラクタまたは代入演算子にアクセスできます。

他のクラスを作成する最もよい方法は、NonCopyableと言うことができます。このクラスはコピーコンストラクタと代入演算子をプライベートにし、クラスを作成してMyClassにNonCopyableクラスのサブクラスを指定させます。

これは、NonCopyableクラスコンストラクタの呼び出しを必要とするため、Myclassの任意のオブジェクトの作成を制限します。また、Myclassメンバ関数はNonCopyableクラスのプライベートコンストラクタにアクセスできないため、この状況も制限されます。

また、NonCopyableクラスを継承することによって、クラスオブジェクトをコピー不可能にする方がより洗練されたものになります。

関連する問題