C ++でのメモリリークを回避するための一般的なガイドライン[終了]


130

C ++プログラムでメモリをリークしないようにするための一般的なヒントは何ですか?動的に割り当てられたメモリを解放する必要があるのはどのようにすればよいですか?


26
私にはかなり建設的なようです。
Shoerob

11
これは建設的です。そして、回答は事実、専門知識、参照などによってサポートされています。そして、賛成票/回答の数を確認してください。
Samitha Chathuranga

回答:


40

メモリを手動で管理する代わりに、適切な場所でスマートポインタを使用してみてください。
見てくださいブーストlibにTR1、およびスマートポインタを
また、スマートポインターはC ++ 11と呼ばれるC ++標準の一部になりました。


1
-std = C ++ 0xの:PARAMを追加するために、G ++ 1つのニーズを使用してコンパイルするには
パヴェルSzczur

または、フラグ値-std = c ++ 11を使用してg ++でコンパイルできます
Prabhash Rathore

200

RAIIとスマートポインターに関するすべてのアドバイスを徹底的に推奨しますが、少しだけレベルの高いヒントも追加したいと思います。管理するのが最も簡単なメモリは、割り当てられていないメモリです。ほとんどすべてが参照であるC#やJavaなどの言語とは異なり、C ++では、できる限りオブジェクトをスタックに配置する必要があります。いくつかの人々(Dr Stroustrupを含む)が指摘しているように、ガベージコレクションがC ++で人気がなかった主な理由は、適切に作成されたC ++が最初から多くのガベージを生成しないためです。

書かないで

Object* x = new Object;

あるいは

shared_ptr<Object> x(new Object);

あなたが書くことができるとき

Object x;

34
これを+10にしたいと思います。これは、今日ほとんどのC ++プログラマーが直面している最大の問題であり、C ++より前にJavaを学んだためだと思います。
クリストファージョンソン

非常に興味深いポイント-私はそんなに少なく、多くの場合、他の言語よりもC ++のメモリ管理の問題持っている理由私は疑問に思っていたが、今なぜ私が見る:それは実際のものはバニラC.のようにスタックに行くことができます
ArtOfWarfare

それで、オブジェクトxを書いたらどうしますか。そして、xを捨てたいですか?xがmainメソッドで作成されたとしましょう。
Yamcha

3
@ user1316459 C ++では、その場でスコープを作成することもできます。あなたがしなければならないすべては、次のように中括弧でxの寿命をラップすることです:{Object x; x.DoSomething; }。最後の '}'の後、xのデストラクタが呼び出され、含まれているすべてのリソースが解放されます。x自体がヒープに割り当てられるメモリである場合、それをunique_ptrでラップして、簡単かつ適切にクリーンアップされるようにすることをお勧めします。
David Peterson

1
ロバート:はい。ロスは「[newを含むコードを書くことはありません]」とは言わず、「[ スタックに置く] ことができるときに、そのようなことはしないでください」と述べました。ヒープ上のラージオブジェクトは、ほとんどの場合、特にパフォーマンスを集中的に使用するコードでは、引き続き適切な呼び出しです。
codetaku

104

RAIIを使用する

  • ガベージコレクションを忘れてください(代わりにRAIIを使用してください)。ガベージコレクタもリークする可能性があることに注意してください(Java / C#で一部の参照を「null」にするのを忘れた場合)、ガベージコレクタはリソースの破棄を支援しません(ハンドルを取得したオブジェクトがある場合)ファイルの場合、Javaで手動で行わなかったり、C#で「破棄」パターンを使用したりしないと、オブジェクトがスコープから外れたときに、ファイルは自動的に解放されません。
  • 「関数ごとに1つのリターン」ルールを忘れてください。これはリークを回避するための良いCのアドバイスですが、例外を使用しているため、C ++では古くなっています(代わりにRAIIを使用してください)。
  • また、「サンドイッチパターン」はCの良いアドバイスですが、 例外を使用しているため、C ++では古くなっています(代わりにRAIIを使用してください)。

この投稿は繰り返しのようですが、C ++では、最も基本的なパターンはRAIIです。

スマートポインターの使用方法を学習します。両方とも、boost、TR1、または低い(ただし十分に効率的である)auto_ptrです(ただし、その制限を知っている必要があります)。

RAIIは、C ++での例外の安全性とリソースの破棄の両方の基礎であり、他のパターン(サンドイッチなど)が両方を提供することはありません(ほとんどの場合、それは何も提供しません)。

RAIIコードと非RAIIコードの比較を以下に示します。

void doSandwich()
{
   T * p = new T() ;
   // do something with p
   delete p ; // leak if the p processing throws or return
}

void doRAIIDynamic()
{
   std::auto_ptr<T> p(new T()) ; // you can use other smart pointers, too
   // do something with p
   // WON'T EVER LEAK, even in case of exceptions, returns, breaks, etc.
}

void doRAIIStatic()
{
   T p ;
   // do something with p
   // WON'T EVER LEAK, even in case of exceptions, returns, breaks, etc.
}

RAIIについて

要約すると(Ogre Psalm33からのコメントの後)、RAIIは3つの概念に依存します。

  • オブジェクトが構築されると、それは機能します!コンストラクタでリソースを取得してください。
  • オブジェクトの破壊で十分です!デストラクタでリソースを解放します。
  • それはすべてスコープについてです!スコープ付きオブジェクト(上記のdoRAIIStaticの例を参照)は、それらの宣言時に構築され、実行がどのように終了(リターン、ブレーク、例外など)しても、実行がスコープを出ると破棄されます。

つまり、正しいC ++コードでは、ほとんどのオブジェクトはで作成されずnew、代わりにスタックで宣言されます。そして、を使用して構築されたものについてはnew、すべてが何らかの形でスコープされます(たとえば、スマートポインターにアタッチされます)。

開発者として、これは実際に非常に強力です(Cで行われるように、またはtry/ finallyを集中的に使用するJavaの一部のオブジェクトに対して)手動のリソース処理を気にする必要がないため...

編集(2012-02-12)

「スコープ付きオブジェクト...破壊されます...出口に関係なく」それは完全に真実ではありません。RAIIをだます方法があります。terminate()のフレーバーはクリーンアップをバイパスします。exit(EXIT_SUCCESS)は、この点に関して矛盾している。

ヴィルヘルムテル

wilhelmtellはそのことについてかなり右である:あり、例外 RAIIをごまかすための方法は、すべてのプロセス急停止につながります。

C ++コードが終了や終了などで散らかされないため、これらは例外的な方法です。または、例外が発生した場合、未処理の例外がプロセスをクラッシュさせ、メモリイメージをそのままクリーンアップしてコアをダンプしたいので、クリーニングした後ではありません。

ただし、これらのケースについては、ほとんど発生しませんが、発生する可能性があるため、引き続き知っておく必要があります。

(誰が呼び出したterminateexitカジュアルなC ++コードに...私は一緒に遊んでたときにその問題に対処することを覚えて?GLUT:このライブラリは非常にC-配向され、これまでのように積極的にC ++開発者は、思いやりのない好きなことは、物事を困難にするために設計していきますスタックデータを割り当てられた、または約「面白い」の決定持つ彼らのメインループから戻ってくることはありませんが ...私は)それについてはコメントはありません


TクラスがRAIIを使用してdoRAIIStatic()がメモリリークしないことを確認してはいけませんか?たとえば、T p(); p.doSandwich(); 私はこれについてあまりよく知りません。
ダニエルO

@Ogre Psalm33:コメントをありがとう。もちろん、そうです。両方のリンクをRAIIウィキペディアページに追加し、RAIIとは何かの簡単な概要も追加しました。
paercebal 2010

1
@Shiftbit:3つの方法、優先順:_ _ _ 1. STLコンテナー内に実際のオブジェクトを配置します。_ _ _ 2.オブジェクトのスマートポインター(shared_ptr)をSTLコンテナー内に配置します。_ _ _ 3.生のポインターをSTLコンテナー内に配置しますが、コンテナーをラップしてデータへのアクセスを制御します。ラッパーはデストラクタが割り当てられたオブジェクトを解放することを確認し、ラッパーアクセサはコンテナへのアクセス/変更時に何も壊れていないことを確認します。
paercebal

1
@Robert:C ++ 03では、子または親関数(またはグローバルスコープ)に所有権を与える必要がある関数でdoRAIIDynamicを使用します。または、ファクトリを介してポリモーフオブジェクトへのインターフェイスを受け取っているとき(正しく書き込まれている場合は、スマートポインターを返します)。C ++ 11では、オブジェクトを移動可能にすることができるため、これは
当てはまりませ

2
@Robert:...スタック上のオブジェクトを宣言しても、オブジェクトが内部でヒープを使用しないことを意味するわけではありません(二重否定に注意してください... :-) ...)。たとえば、Small String Optimizationで実装されたstd :: stringは、小さな文字列(約15文字)に対して「クラスのスタック上」にバッファーを持ち、大きな文字列に対してヒープ内のメモリへのポインターを使用します...ただし、外側から見ると、std :: stringは引き続きスタックで(通常)宣言する値型であり、整数と同じように使用します(多相クラスのインターフェイスを使用するのとは対照的です)。
paercebal 2014年

25

boostのスマートポインターなどのスマートポインターを確認する必要があります。

の代わりに

int main()
{ 
    Object* obj = new Object();
    //...
    delete obj;
}

boost :: shared_ptrは、参照カウントがゼロになると自動的に削除されます。

int main()
{
    boost::shared_ptr<Object> obj(new Object());
    //...
    // destructor destroys when reference count is zero
}

私の最後のメモ、「参照カウントがゼロのとき、これは最もクールな部分です。したがって、オブジェクトの複数のユーザーがいる場合、オブジェクトがまだ使用されているかどうかを追跡する必要はありません。共有ポインタ、それは破壊されます。

ただし、これは万能薬ではありません。ベースポインターにアクセスできますが、それが何をしているかに自信がない限り、それをサードパーティのAPIに渡したくないでしょう。多くの場合、スコープの作成が完了した後に、他のスレッドに「投稿」するための作業が行われます。これは、Win32のPostThreadMessageと共通です。

void foo()
{
   boost::shared_ptr<Object> obj(new Object()); 

   // Simplified here
   PostThreadMessage(...., (LPARAM)ob.get());
   // Destructor destroys! pointer sent to PostThreadMessage is invalid! Zohnoes!
}

いつものように、あらゆるツールで思考キャップを使用してください...



11

ほとんどのメモリリークは、オブジェクトの所有権と有効期間が明確でないことが原因です。

最初にすることは、できる限りスタックに割り当てることです。これは、何らかの目的で単一のオブジェクトを割り当てる必要があるほとんどの場合を扱います。

オブジェクトを「新規」にする必要がある場合、ほとんどの場合、オブジェクトには残りの存続期間中、明らかな所有者が1人います。この状況では、ポインターによって格納されたオブジェクトを「所有」するように設計されたコレクションテンプレートの束を使用する傾向があります。これらはSTLベクトルとマップコンテナーで実装されていますが、いくつかの違いがあります。

  • これらのコレクションをコピーまたは割り当てることはできません。(オブジェクトが含まれている場合)。
  • オブジェクトへのポインタがそれらに挿入されます。
  • コレクションが削除されると、最初にデストラクタがコレクション内のすべてのオブジェクトで呼び出されます。(破壊されて空でない場合にアサートする別のバージョンがあります。)
  • ポインタを格納するため、継承されたオブジェクトをこれらのコンテナに格納することもできます。

私のSTLの欠点は、Valueオブジェクトに重点が置かれていることですが、ほとんどのアプリケーションでは、オブジェクトはこれらのコンテナーでの使用に必要な意味のあるコピーセマンティクスを持たない一意のエンティティです。


10

ああ、あなたはあなたの若い子供たちとあなたの新しくできたガベージコレクター...

「所有権」に関する非常に強力なルール-どのオブジェクトまたはソフトウェアの一部がオブジェクトを削除する権利を持っているか。コメントと賢明な変数名を明確にして、ポインターが「所有している」か「見ているだけで触らない」かを明確にします。誰が何を所有しているのかを判断するために、すべてのサブルーチンまたはメソッド内の「サンドイッチ」パターンをできる限り従います。

create a thing
use that thing
destroy that thing

場合によっては、さまざまな場所で作成および破棄する必要があります。それを避けるのは難しいと思います。

複雑なデータ構造を必要とするプログラムでは、「所有者」ポインタを使用して、他のオブジェクトを含むオブジェクトの厳密な明確なツリーを作成します。このツリーは、アプリケーションドメインの概念の基本的な階層をモデル化しています。3Dシーンがオブジェクト、ライト、テクスチャを所有している例。プログラムが終了するレンダリングの最後に、すべてを破壊する明確な方法があります。

他の多くのポインタは、あるエンティティが別のエンティティにアクセスする必要があるとき、アレイ上をスキャンするために、必要に応じて定義されます。これらは「見ているだけ」です。3Dシーンの例-オブジェクトはテクスチャを使用していますが、所有していません。他のオブジェクトが同じテクスチャを使用する場合があります。オブジェクトを破棄しても、テクスチャは破棄されませ

はい、それは時間がかかりますが、それは私がやっていることです。メモリリークやその他の問題が発生することはほとんどありません。しかし、私は高性能の科学、データ収集、およびグラフィックスソフトウェアの限られた分野で働いています。私は、銀行やeコマース、イベント駆動型GUI、高度なネットワーク非同期カオスなどのトランザクションを処理することはあまりありません。多分新しい手間のかかる方法はそこに利点があります!


私は完全に同意します。組み込み環境での作業では、サードパーティのライブラリを利用できない場合もあります。
サイモン

6
同意しません。「それを使う」の部分で、もしもリターンや例外が投げられたら、割り当て解除を逃してしまいます。パフォーマンスに関しては、std :: auto_ptrを使用してもコストはかかりません。私があなたと同じようにコーディングすることは決してありません。100%と99%の安全なコードに違いがあるだけです。:-)
paercebal 2008

8

すばらしい質問です。

c ++を使用していて、リアルタイムのCPUおよびメモリの大容量アプリケーション(ゲームなど)を開発している場合は、独自のメモリマネージャを作成する必要があります。

あなたができるより良いことは、様々な作者のいくつかの興味深い作品をマージすることだと思います、私はあなたにいくつかのヒントを与えることができます:

  • 固定サイズのアロケーターについては、ネット上のあらゆる場所で頻繁に議論されています

  • 小さなオブジェクトの割り当ては、2001年にAlexandrescuによって彼の完璧な本「Modern c ++ design」で紹介されました。

  • (ソースコードが配布された)大きな進歩は、Dimitar Lazarovによって書かれた「High Performance Heap allocator」という名前のGame Programming Gem 7(2008)の驚くべき記事にあります。

  • リソースのすばらしいリストはこの記事で見つけることができます

noobの役に立たないアロケータを自分で書き始めないでください...最初に自分自身を文書化してください。


5

C ++のメモリ管理で一般的になっている1つの手法はRAIIです。基本的には、コンストラクター/デストラクターを使用してリソース割り当てを処理します。もちろん、例外の安全性のためにC ++には他にも不愉快な詳細がありますが、基本的な考え方はかなり単純です。

問題は一般的に所有権の1つに帰着します。Scott MeyersによるEffective C ++シリーズとAndrei AlexandrescuによるModern C ++ Designを読むことを強くお勧めします。


5

リークを防ぐ方法はすでにたくさんありますが、リークの追跡に役立つツールが必要な場合は、以下をご覧ください。


BoundsCheckerは404ingです。
TankorSmash 2014

4

どこでもできるユーザースマートポインター!メモリリークのクラス全体がなくなるだけです。


4

プロジェクト全体でメモリ所有権のルールを共有し、把握します。COMルールを使用すると、最高の一貫性が得られます([in]パラメータは呼び出し元が所有し、呼び出し先はコピーする必要があります。[out]パラメータは呼び出し元が所有し、呼び出し先は参照を保持している場合はコピーを作成する必要がありますなど)。


4

valgrindは、実行時にプログラムのメモリリークをチェックするための優れたツールでもあります。

Linuxのほとんどの種類(Androidを含む)とDarwinで利用できます。

を使用してプログラムの単体テストを作成する場合は、テストに対してvalgrindを体系的に実行する習慣を身に付ける必要があります。初期段階で多くのメモリリークを回避できる可能性があります。また、通常は、完全なソフトウェアで行う簡単なテストでそれらを特定する方が簡単です。

もちろん、このアドバイスは他のメモリチェックツールに対しても有効です。


3

また、stdライブラリクラス(ベクターなど)がある場合は、手動で割り当てられたメモリを使用しないでください。そのルールに違反していないかどうか、仮想デストラクタがあることを確認してください。


2

何かにスマートポインターを使用できない、または使用できない場合(これは大きな赤い旗になるはずです)、次のコードを入力します。

allocate
if allocation succeeded:
{ //scope)
     deallocate()
}

それは明白ですが、スコープにコードを入力する前に必ず入力してください


2

これらのバグのよくある原因は、オブジェクトへの参照またはポインタを受け入れるが所有権が不明確なメソッドがある場合です。スタイルとコメントの規則により、これが起こりにくくなる場合があります。

関数がオブジェクトの所有権を取得する場合を特殊なケースとします。これが発生するすべての状況で、ヘッダーファイルの関数の横に、これを示すコメントを必ず記述してください。ほとんどの場合、オブジェクトを割り当てるモジュールまたはクラスが、オブジェクトの割り当てを解除する責任を負うように努める必要があります。

場合によっては、constを使用すると大きな効果があります。関数がオブジェクトを変更せず、戻り後も持続するオブジェクトへの参照を保存しない場合は、const参照を受け入れます。呼び出し元のコードを読むと、関数がオブジェクトの所有権を受け入れていないことが明らかになります。同じ関数で非constポインターを受け入れるようにすることもできます。呼び出し側は、呼び出し先が所有権を受け入れたと想定している場合と想定していない場合がありますが、const参照の場合は問題ありません。

引数リストでは非const参照を使用しないでください。呼び出し元のコードを読み取るときに、呼び出し先がパラメーターへの参照を保持していた可能性があることは非常に不明確です。

参照カウントポインターを推奨するコメントには同意しません。これは通常は正常に機能しますが、バグがあり機能しない場合、特にデストラクタがマルチスレッドプログラムなどで重要なことを行う場合は特にそうです。難しいことではない場合は、必ず参照カウントが不要になるように設計を調整してください。


2

重要度順のヒント:

-Tip#1デストラクタを「仮想」として宣言することを忘れないでください。

-Tip#2 RAIIを使用する

-Tip#3 boostのスマートポインターを使用する

-Tip#4独自のバグのあるスマートポインターを記述せずに、ブーストを使用します(現在進行中のプロジェクトでは、ブーストを使用できません。自分のスマートポインターをデバッグする必要があり、間違いなく取りません。再び同じルートですが、今度は依存関係にブーストを追加できません)

-Tip#5(数千のオブジェクトを持つゲームのように)カジュアル/非パフォーマンスが重要な場合は、Thorsten Ottosenのブーストポインターコンテナーを確認してください

-Tip#6 Visual Leak Detectionの「vld」ヘッダーなど、選択したプラットフォームのリーク検出ヘッダーを見つける


トリックを見逃しているかもしれませんが、「ゲーム」と「非パフォーマンスクリティカル」を同じ文に含めるにはどうすればよいですか?
Adam Naylor、

もちろんゲームは重要なシナリオの例です。そこを明確にすることができなかった可能性があります
Robert Gould、

ヒント#1は、クラスに少なくとも1つの仮想メソッドがある場合にのみ適用する必要があります。ポリモーフィック継承ツリーの基本クラスとして機能することを意図していないクラスに、役に立たない仮想デストラクタを課すことはありません。
2015

1

可能であれば、boost shared_ptrと標準C ++ auto_ptrを使用してください。それらは所有権の意味論を伝えます。

auto_ptrを返すと、呼び出し元にメモリの所有権を与えることを伝えます。

shared_ptrを返すときは、それを参照していることと、所有権の一部を担っていることを発信者に伝えますが、それだけが責任ではありません。

これらのセマンティクスはパラメーターにも適用されます。呼び出し元がauto_ptrを渡すと、所有権が付与されます。


1

そもそもメモリリークを回避する方法(スマートポインタなど)について言及している人もいます。しかし、プロファイリングおよびメモリ分析ツールは、多くの場合、メモリの問題が発生した後、それを追跡する唯一の方法です。

Valgrind memcheckは優れた無料のソフトウェアです。


1

MSVCの場合のみ、各.cppファイルの先頭に次を追加します。

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

次に、VS2003以降でデバッグすると、プログラムの終了時にリークが通知されます(新規/削除を追跡します)。これは基本的なことですが、以前は役に立ちました。



1

メモリを手動で管理する場合は、次の2つの場合があります。

  1. 私はオブジェクトを作成し(おそらく間接的に、新しいオブジェクトを割り当てる関数を呼び出すことによって)、それを使用し(または、私が呼び出す関数がそれを使用して)、それを解放します。
  2. 誰かが私に参照を与えたので、私はそれを解放するべきではありません。

これらの規則に違反する必要がある場合は、文書化してください。

それはすべてポインタの所有権についてです。


1
  • オブジェクトを動的に割り当てないようにしてください。クラスに適切なコンストラクターとデストラクターがある限り、クラスへのポインターではなく、クラス型の変数を使用します。コンパイラーがそれを行うため、動的な割り当てと割り当て解除を避けます。
    実際、これは「スマートポインタ」が使用するメカニズムでもあり、他の一部のライターではRAIIと呼ばれています;-)。
  • オブジェクトを他の関数に渡すときは、ポインターよりも参照パラメーターを優先してください。これにより、いくつかのエラーが回避されます。
  • 可能であれば、特にオブジェクトへのポインタなどのパラメータconstを宣言します。この方法では、オブジェクトを「誤って」解放することはできません(constをキャストする場合を除き、;-)))。
  • メモリの割り当てと割り当て解除を行うプログラム内の場所の数を最小限に抑えます。例:同じタイプを数回割り当てたり解放したりする場合は、そのための関数(またはファクトリメソッド;-))を記述します。
    このようにして、必要に応じて、デバッグ出力(アドレスの割り当てと割り当て解除など)を簡単に作成できます。
  • ファクトリー関数を使用して、単一の関数からいくつかの関連クラスのオブジェクトを割り当てます。
  • クラスに仮想デストラクタを持つ共通の基本クラスがある場合は、同じ関数(または静的メソッド)を使用してすべてを解放できます。
  • purifyなどのツールでプログラムをチェックします(残念ながら、多くの$ /€/ ...)。

0

メモリ割り当て関数をインターセプトして、プログラムの終了時に解放されていないメモリゾーンがあるかどうかを確認できます(すべてのアプリケーションに適しているわけではありません)。

また、オペレーターのnewやdeleteなどのメモリ割り当て関数を置き換えることで、コンパイル時に行うこともできます。

たとえば、このサイト [C ++でのメモリ割り当てのデバッグ]を確認してください。注:削除演算子にも次のようなトリックがあります。

#define DEBUG_DELETE PrepareDelete(__LINE__,__FILE__); delete
#define delete DEBUG_DELETE

一部の変数にはファイルの名前を格納できます。また、オーバーロードされた削除演算子が呼び出された場所がどこであるかを知ることができます。この方法で、プログラムからのすべての削除とmallocのトレースを取得できます。メモリチェックシーケンスの最後に、割り当てられたメモリのどのブロックが「削除」されていないかをレポートできるはずです。ファイル名と行番号で識別できます。

Visual StudioでBoundsCheckerのようなものを試すこともできます。これは非常に興味深く、使いやすいものです。


0

すべての割り当て関数を、前に短い文字列を追加し、最後に歩哨フラグを追加するレイヤーでラップします。したがって、たとえば、「myalloc(pszSomeString、iSize、iAlignment);またはnew( "description"、iSize)MyObject();を呼び出して、指定したサイズに加えて、ヘッダーとセンチネルに十分なスペースを内部的に割り当てます。もちろん、 、非デバッグビルドの場合はコメントアウトすることを忘れないでください!これを行うには少し多くのメモリが必要ですが、利点はコストをはるかに上回ります。

これには3つの利点があります。1つ目は、特定の「ゾーン」に割り当てられているが、それらのゾーンを解放する必要があるときにクリーンアップされていないコードをすばやく検索することにより、リークしているコードを簡単かつ迅速に追跡できることです。また、すべての標識が無傷であることを確認することにより、境界が上書きされたことを検出することも役立ちます。これにより、よく隠されたクラッシュやアレイのミスステップを見つけようとするときに何度も私たちを救いました。3番目の利点は、メモリの使用状況を追跡して大物選手が誰であるかを確認することです。たとえば、MemDumpの特定の説明を照合すると、「サウンド」が予想よりもはるかに多くのスペースを占めていることがわかります。


0

C ++はRAIIを念頭に置いて設計されています。C ++でメモリを管理するためのより良い方法はないと思います。ただし、ローカルスコープに非常に大きなチャンク(バッファーオブジェクトなど)を割り当てないように注意してください。スタックオーバーフローを引き起こす可能性があり、そのチャンクの使用中に境界チェックに欠陥がある場合は、他の変数を上書きしたり、アドレスを返したりして、あらゆる種類のセキュリティホールにつながる可能性があります。


0

さまざまな場所での割り当てと破棄に関する唯一の例の1つは、スレッドの作成(渡したパラメーター)です。しかし、この場合でも簡単です。スレッドを作成する関数/メソッドは次のとおりです。

struct myparams {
int x;
std::vector<double> z;
}

std::auto_ptr<myparams> param(new myparams(x, ...));
// Release the ownership in case thread creation is successfull
if (0 == pthread_create(&th, NULL, th_func, param.get()) param.release();
...

ここでは代わりにスレッド関数

extern "C" void* th_func(void* p) {
   try {
       std::auto_ptr<myparams> param((myparams*)p);
       ...
   } catch(...) {
   }
   return 0;
}

かなり簡単ですね。スレッドの作成が失敗した場合、リソースはauto_ptrによって解放(削除)されます。それ以外の場合、所有権はスレッドに渡されます。スレッドが非常に高速で、作成後にリソースが解放される前に

param.release();

メイン関数/メソッドで呼び出されますか?何もない!割り当て解除を無視するようにauto_ptrに「伝える」ためです。C ++のメモリ管理は簡単ですか?乾杯、

えま!


0

他のリソース(ハンドル、ファイル、db接続、ソケットなど)を管理するのと同じ方法でメモリを管理します。GCもそれらを支援しません。


-3

任意の関数からの正確な1つの戻り。そうすることで、割り当てを解除して、見逃すことはありません。

それ以外の場合、間違いを犯すのは簡単です。

new a()
if (Bad()) {delete a; return;}
new b()
if (Bad()) {delete a; delete b; return;}
... // etc.

あなたの答えはここのサンプルコードと一致しませんか?「1回のみ返品」という回答には同意しますが、コード例では何をすべきでないかを示しています。
サイモン

1
C ++ RAIIのポイントは、ユーザーが記述した種類のコードを回避することです。Cでは、これはおそらく正しいことです。しかし、C ++では、コードに欠陥があります。例:new b()がスローするとどうなりますか?あなたはリークします。
paercebal 2008
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.