2011-02-10 8 views
3

私は古いC#プログラマとCプログラマ(動的メモリ割り当てなし)ですが、Visual C++プログラミングについて少しは学びたいと思います。気にする質問は、C++でのメモリ管理に関連しています。 C#では、ガベージコレクタがメモリ管理を担当しますが、C++では割り当てられたメモリを解放する責任を負っている人に関するルールがいくつか設定されている必要があります。私はC#のいくつかの典型的なシナリオを持っています:Visual C++のネイティブメモリ管理のベストプラクティス

  1. オブジェクトは何らかのコンテナに入れられます。誰がメモリを解放する責任があります。複数のクラスが同じオブジェクトを共有する場合はどうなりますか?

  2. 工場パターン。親クラスに子オブジェクトを作成するメソッドがあるクラス階層を使うのが好きですか?

  3. 呼び出したメソッドに、返されたオブジェクトが呼び出し先/呼び出し元の所有権を持つことを提案する方法はありますか。

これについていくつかのヒントをお聞きしたいと思います。

答えて

12

コードを正しく書くと、これは少なくとも直接は心配する必要はありません。メモリ管理やその他のリソース管理を完全に自動的に処理するライブラリ機能が用意されているので、不要にする必要はありません。

C++はガベージコレクタよりはるかに優れています。すべてのオブジェクトを確定的に破壊し、(多くの一般的な実装では)許可するガベージコレクションとは異なり、決定的な破壊を使用してすべてのリソースのライフタイムを自動的に管理します。自動的にメモリを管理し、確定的なクリーンアップを必要とする他のすべてのリソースを手動で管理します。

オブジェクトを動的に割り当てる場合は、スマートポインタを使用してそのライフタイムを管理します。所有権を共有する必要がない場合は、std::unique_ptrを使用して所有者から所有者に所有権を譲渡することができます。所有権を共有する必要がある場合は、std::shared_ptrを使用できます。これは参照カウント手法を使用して共有所有権を維持します。

心に留めておくには、2つの重要なルールがあります:あなたはC++プログラムでdeleteを書くことがある場合

  • は、コードはほぼ確実に間違っています。 C++では、メモリを含むすべてのリソースの自動有効期間管理機能が提供されています。 deleteの唯一の場所は、リソース所有コンテナが実装されているライブラリコードと潜在的には低レベルのコードです。

  • 可能であれば、オブジェクトへのポインタではなくオブジェクトを扱うことをお勧めします。可能な限り、明示的な動的割り当ては避けてください。 C++は、ほとんどのオブジェクトがヒープ上に作成されるC#やJavaのような言語ではありません。 C++では、(自動変数を使用して)スタックにオブジェクトを作成し、それらを値で返す方が良い場合がよくあります。

はあなたの特定のシナリオに答えるために:

オブジェクトはいくつかの種類の容器に入れています。誰がメモリを解放する責任があります。複数のクラスが同じオブジェクトを共有する場合はどうなりますか?

可能であれば、オブジェクトを指すポインタではなく、オブジェクト自体をコンテナに格納することをお勧めします。何らかの理由でオブジェクトへのポインタを格納する必要がある場合は、スマートポインタのコンテナ(たとえば、std::vector)を使用する必要があります。コンテナが動的に割り当てられたオブジェクトの単独の所有権を持っている場合は、std::vector<std::unique_ptr<T>>を使用できます。コンテナがオブジェクトの所有権を共有する場合はstd::vector<std::shared_ptr<T>>を使用できます。

Factoryパターン。親クラスに子オブジェクトを作成するメソッドがあるクラス階層を使うのが好きですか?

これは、前のシナリオと違いはありません:あなたは木を持っている場合、それは(あなたが動的に割り当てられた子供が必要な場合やstd::vector<std::unique_ptr<T>>)子供を所有するためにstd::vector<T>を使用することは非常に簡単です。

呼び出し元のメソッドに、返されたオブジェクトが呼び出し先/呼び出し元の所有権を持つことを提案する方法はありますか。

オブジェクトが(std::unique_ptrなどの)呼び出し先によって所有されている場合は、そのスマートポインタを返すことができます。そうすることで、所有者が発信者に転送されます。

オブジェクトの共有所有権がある場合(たとえば、std::shared_ptr)、スマートポインタを返すと、呼び出し元が所有者の1人になります。オブジェクトを所有している最後の所有者(オブジェクトを所有しているstd::shared_ptrを破棄またはリセットするなど)によって、オブジェクトが自動的に破棄されます。

+1

はい、shared_ptrのは素晴らしいことです。しかし、生ポインタを使用する場合は、それを記録してください。コンテナは、データを所有しているかどうか、またそれを削除する必要があるかどうかについて文書化する必要があります。ポインターを返すメソッドは、呼び出し元がメモリーを削除するかどうかを記録する必要があります。 – Tim

+5

@Tim:99.999%のコードでは、生ポインタを扱うべきではありません。あなたが低レベルのシステムコードを書いていない場合や独自のスマートポインタや他のRAIIコンテナを実装していない場合は、ほぼ確実にスマートポインタを使用するべきです。 –

+0

'std :: unique_ptr'は素晴らしいものですが、残念ながらC++ 0xにしか存在しません。なぜなら、移動セマンティクスを使用するからです。 C++ 03(Alexandrescuの 'mojo_ptr'のような)でそれを実装しようとすると、コピーの構築が禁止され、これらのスマートポインタがコンテナに格納されなくなります。悲しいこと。 –

3

ジェームズの答えは正しいです。しかし、彼は彼が議論している技術の名前は言及していません。 RAIIは、C++のメモリ(およびその他のリソース)管理にとって非常に重要な概念です。 RAIIはResource Acquisition Is Initializationの略です。しかし、それは少し誤解を招くので、名前はあなたを混乱させてはいけません。

ウィキペディアには、読み取りを開始するには良い場所です: RAII on Wikipedia

+0

あなたが正しい;私はその名前に言及することを全く忘れていた。良いキャッチ。 –

関連する問題