2009-06-08 15 views
5

私はベクトルとの関係でメモリ管理と非常に混同しており、いくつかの基本的な概念を説明することができます。C++メモリ管理とベクトル

私は大きなベクトルを使用するプログラムを持っています。 私は新しいオペレータとのベクトルを作成し、戻ってメモリを取得するためにを削除とプログラムの最後にそれらを解放。プログラムはラインを見逃すことになる、削除、クラッシュしたり、これまでどのような理由のために中止されてしまった場合

私の質問は、、でもこのシナリオでメモリを回復する方法があります。

新しいというキーワードを使用して割り当てた他の大きなベクトルもあります。 これはヒープ上に作成されますが、メモリ管理が「フードの下で」扱われるため、とにかく割り当てを解除する必要はありません。 しかし、私は私がRAMを失うプログラムを実行するたびにこれが当てはまるとは思いません。

だから私の2番目の質問は、新しいキーワードを指定せずに作成したベクトルが本当に自分のデバイスに左にと、コードが途中流れを中断された場合でも、自分自身後にクリアするために、信頼することが可能です。

そして私はちょうどベクターは、自動的にヒープ上に作成されている場合は、なぜあなたは彼らと新しいキーワードを使用している心に生まれた3番目の質問を想定? 読んでいただきありがとうございます。 ben

+2

「プログラムを実行するたびにRAMが失われます」ということは、「プログラムを終了するまで使用可能なRAMが小さくなる」または「プログラムを終了しても利用可能なRAMが小さくなることを意味しますか?次回は走って、いつかはいつまでもRAMを残さないだろうか? –

+0

私はマックスの質問をセコンディングしています。 Windows私は実際には、必要がない限り、終了したプログラムをアンロードしないと考えています。そうすれば、彼らは最初からすぐに立ち上がります。 –

+0

"そして、私はちょうど心に浮かんだ3番目の質問は、ベクトルが自動的にヒープ上に作成された場合、なぜ新しいキーワードをそれらと一緒に使うのかということです。 ベクトルを現在のスコープ外のポイントに渡す必要がある場合にのみ、これを行う必要があります。これは実際には比較的稀です。 – rlbond

答えて

13

私はあなたの質問がstd :: vector < T>(配列T []とは対照的)であると思っています。

  1. アプリケーションがクラッシュしたり、何らかの理由でアボートしたりすると、OSはメモリを再要求します。そうでない場合、本当にまれなOSを使用しており、バグを発見しました。
  2. ベクトル自体で使用されているメモリと含まれているオブジェクトのメモリを区別する必要があります。ベクタは、ヒープ上またはスタック上に作成したように指定することができます。含まれる要素に割り当てるメモリは常にヒープ上にあります(独自のアロケータを用意しない限り)。ベクトルによって割り当てられたメモリは、vectorの実装によって管理されます。もしベクトルが破壊された場合(スタック上のベクトルのスコープから外れるか、またはヒープ上のベクトルを削除するため)、デストラクタはすべてのメモリが解放されます。
+1

多くの組み込みOSと多くのRTOSは、プロセスがクラッシュしたときにリソースをクリーンアップしません。 –

3

プログラムによって作成されたメモリは、終了時にリリースされます。これはオペレーティングシステムの機能で、使用しているプログラミング言語とは関係ありません。

「私のプログラムを実行するたびに私は緩やかなRAMが必要です」というのは、他のいくつかの効果が原因です。

  • あなたは彼らはあなたがそれらを現在の関数の終了後も持続したい
  • に解放されたときに制御したい:二つの理由 - あなたは「新しい」を使用したい理由として

+1

Tobiasに与えられたコメントと同じです。ほとんどの組み込みOSと多くのRTOSは、プロセスがクラッシュしたときにリソースをクリーンアップしません。 –

+0

+1多くの人が気づいていないことを指摘しています。仮想メモリマネージャーは、しばしば当然と考えられている高級品です。 – Void

3

言語配列についてではなく、std :: vectorについて説明します。

  1. と、プログラムがクラッシュし、OSはそのメモリ
  2. のstd ::ベクトルを回復するには、それが割り当てるメモリを解放します。ポインタを格納している場合、ポインタは削除されません。
  3. ベクトルは他の変数と同様に作成され、ベクターであるためヒープには含まれません。
4

はい、ベクターは自分自身の後にクリーンアップすることができます。

HOWEVERスタッフベクタ保持がそれ自身の後にクリーンアップするのは信頼できません。クリーンアップする必要があるのは、アプリケーションの外部で持続するものです。その記憶があれば、これは心配ではありません。 XMLタグがすべて閉じていることを確認すると、OSはあなたを助けることができなくなります。例えば

、何がこのようないくつかのグラグラロックオブジェクトのベクトルがある場合:そのときに行わ

class CLock 
    { 
    public: 
     CLock() {} 
     ~CLock() {} 

     void Lock(...) {...} 

     void Unlock(...) {...} 
    }; 

    std::vector<CLock> myLockVec; 

がどのように時計のノウハウのあなたのベクトルはすべてのロックを解除するでしょうか?ベクタはロックについて知るために構築されていません。

これはポインタのベクトルを持つと同じような状況は基本的に次のとおりです。

std::vector<int*> myIntVec; 

どのようにベクトルがここにポインタ削除されているとNULL'd、そしてどれが本当に存在している知っているのですか?おそらくいくつかは削除され、特別な値0xdeadbeefに設定されています。つまり、削除されています。

ポイントはベクトルがこれを知る手段を持たないか、その要素がポインタまたはロックであることを知ることができません。それらは、デフォルトのコンストラクタを持ち、コピー可能なものである必要があり、ベクトルがその要素に持つ他の要件を満たしている必要があります。

解決策は、HOLDSベクタがクリーンアップを担当する必要があることを確認することです。これは、RAIIと呼ばれます。リソース割り当ては初期化です。ここで重要なことに、リソース破壊は割り当て解除です。上記のClockの例では、答えは明らかです。終了したら必ずアンロックしてください!

class CLock 
{ 
     ... 
     ~Clock() 
     { 
      if (locked) 
      { 
       Unlock(); 
      } 
     } 
} 

しかし、そのポインタはそれほど明白ではありません。解決策は、smart_ptrクラスの中でポインタを包むことです。これらの中で最も多くはboost family of smart ponitersです。

class CSmartPointer<T> 
{ 
     CSmartPointer(T* rawPtr) 
     { 
     m_ptr = rawPtr; 
     } 

     ~CSmartPointer() 
     { 
     delete m_ptr; 
     } 
} 

その他の機能は、このような参照カウントとしてポインタをプレイさせられるが、上記の例では、あなたの問題の性質の要点を与える必要があり、その一般的にどのように解決しました。

1

「メモリが紛失しました」の場合は、@ RichieHindieとは何ですか? 2番目の質問については

NEWキーワードを指定せずに作成したベクトルが本当に自分 自分のデバイスに左とコード が半ば流れ

中止された場合でも、自分自身後にクリアするために信頼することができます

通常のプログラム終了(例外による終了を含む)では、デストラクタが実行されることが保証されますが(理論的には静的なデータに関しても、実際には問題が生じることがあります)、pの十分なハードクラッシュロセスはいかなる動作も保証することはできません。例えば、kill -9であることが保証されたは、デストラクタなどを実行する機会を与えずにプログラムをできるだけ早く終了させることができます。

+0

未処理の例外(ランタイムが最終的にterminate()を呼び出す原因となる例外)によっては、デストラクタが実行されないことがあります。この場合のスタックのアンワインド動作は、実装定義です。 – ASk

8

ベクターを作成するのにnewを使用しないでください。それらをスタックに置くだけです。

ベクトルのデストラクタは、自動的にベクトルの各要素のデストラクタを呼び出します。したがって、オブジェクトを自分で削除する心配はありません。しかし、ポインターのベクトルを持っている場合、ポインターが参照するオブジェクトはではなく、がクリーンアップされます。ここにいくつかのコード例があります。わかりやすくするために、私はほとんどの細部を省いています:

class HeapInt 
{ 
    public: 
     HeapInt(int i) {ptr = new int(i);} 
     ~HeapInt() {delete ptr;} 
     int& get() {return *ptr;} 
    private: 
     int* ptr; 
}; 

int main() 
{ 
    // this code DOES NOT leak memory 
    std::vector<HeapInt> vec; 
    for (int i = 0; i < 10; ++i) 
    { 
     HeapInt h(i); 
     vec.push_back(h); 
    } 
    return 0; 
} 

メイン()が例外をスローしたとしても、メモリは失われません。しかし、このコードリークメモリを行います。

たちの2の ​​3210
+0

これは必ずしも機能しません。 –

+4

はい、疑問を尋ねる人は、ベクタが通常スタックに置かれるべきであることを明確には分かりません。 – rlbond

+0

2番目の例はどのようにメモリをリークしますか?プログラムが終了し、OSがメモリを再利用するか、メモリ管理に関して何か恐ろしいほど重要なことがありません。 –

2

一つはここに少し混乱しています。

std :: vectorを使用している場合、その要素に手動でメモリを割り当てる必要はありません。余分なスペースは、push_back()を実行するたびに必要に応じて自動的に割り当てられます。何らかの理由ですべてのスペースが事前に割り当てられている必要がある場合は、reserve()を呼び出すことができます。いずれにしても、ベクターが破壊されたときに自動的に解放されます。

新しいstd :: vectorを実行している場合は、ベクターへのポインタが取得されています。それは、他のどのクラスでもnewを呼び出すことと変わりありません。そのクラスのオブジェクトへのポインタを作成すると、deleteを呼び出すとdestructedになります。そのような動作が気に入らない場合は、スタックにベクターを作成してみてください。

1

"new"を使用したい場合には、ベクタがクラスのメンバ変数である場合があります。追加のセマフォとしてNULLを使用することができます(たとえば、オンデマンドでの作成時)。あなたのクラスでベクトルの使用量がまばらになっている場合は、本当に必要な場合を除いて作成しなくても、すべてのインスタンスで4バイトのペナルティを追加するだけでなく、ポインタの間接指定の実行時のペナルティを犠牲にしてメモリを節約できます。