2012-01-10 10 views
3
、私は次のコードで最初のメモリを解放しません削除理由を知りたいと思い

"元の"ポインタでdeleteを呼び出す必要があるのはなぜですか?

#include <list> 
#include <stdio.h> 

struct abc { 
    long a; 

    abc() { 
     puts("const"); 
    } 
    ~abc() { 
     puts("desc"); 
    } 
}; 

int main() { 

    std::list<abc*> test; 

    abc* pA = new abc; 
    printf("pA: 0x%lX\n", (unsigned long int)pA); 
    test.push_back(pA); 

    abc* pB = test.back(); 

    printf("pB: 0x%lX\n", (unsigned long int)pB); 
    delete pB; // just ~abc() 

    test.pop_back(); 

    delete pA; // ~abc() and free (works) 

    puts("before double-free"); 

    delete pA; // ~abc() and second free (crash) 

    return 0; 
} 

出力は次のとおりです。

const 
pA: 0x93D8008 
pB: 0x93D8008 
desc 
desc 
before double-free 
desc 
*** glibc detected *** ./test: double free or corruption (fasttop): 0x093d8008 *** 
... 

は私もfree()が、同じ行動でそれを試してみました。

+0

同じオブジェクトを3回削除していますか? 'new'ごとに、** one ** deleteを持つべきです。 – ronag

+4

"なぜ次のコードで最初の削除はメモリを解放しません" - そうです。 – Mat

+0

メモリはちょうどいいから解放されます。*最初の時間。 – Jon

答えて

4
delete pA; // ~abc() and free (works) 

puts("before double-free"); 

delete pA; // ~abc() and second free (crash) 

これらdelete文はdelete pBを追記必要ないです。 delete pBはデストラクタだけを呼び出すと誤解しています。いいえ、デストラクタを呼び出し、メモリを解放します。すでにdelete pBを書いてきたので、

はまた、次の2つの別のdelete式は何が起こることができることを意味、undefined behaviorを呼び出す:プログラムクラッシュしない場合があり!

は、これらのトピックを見てください:newに割り当てられた

+0

私は知っていますが、ダブルフリーであればプログラムはクラッシュするはずですが、そうではありません。 – Zaffy

+1

@quarry:なぜそれがクラッシュすると思いますか?これは未定義の動作です。 –

+1

@quarry:いいえ、すでに解放されているものを解放しようとすると、未定義の動作が呼び出されます。プログラムがクラッシュしたり、メッセージが表示されたり、悪魔があなたの鼻から飛び出すことがあります。 – Hasturkun

1

まず、次のことができないfreeメモリ、あなたはdeleteを使用する必要があります。

第2に、glibcがすぐにダブルフリーを検出しないため、を知っていますdelete pB;はそれを解放していません。それはdeleteのもので、自分のログから毎回deleteに同じアドレスを渡しています。

第3に、実際に何を達成しようとしていますか?

2

最初の削除では、ポインタが無効な状態になります。したがって、そのポインタを使用すると未定義の動作になります。 (最初のコメントで指摘したように)

int* p = new int; 
delete p; 
delete p; //undefined behaviour 

これは、標準による微細であることが保証されています

int* p = new int; 
delete p; 
p = 0; 
delete p; //fine 
+0

2番目のスニペットは標準で保証されています。 –

+0

@SteveJessopそれを指摘してくれてありがとう。私は答えを編集しました。 –

1

それはあなたが二回にdeleteを呼び出すために持っていたあなたのコンパイラ/プラットフォームのちょうどindiosyncracyですglibcpAを訴え...例えば、gccバージョンのi686-りんごdarwin10-GCC-4.2.1とOSX 10.6.8である私の現在のプラットフォーム上で、私は次のような出力が得られます。

const 
pA: 0x100100080 
pB: 0x100100080 
desc 
desc 
test(14410) malloc: *** error for object 0x100100080: pointer being freed was not allocated 
*** set a breakpoint in malloc_error_break to debug 
Abort trap 

ですから、未定義の動作で標準の結果によって、あなたがNULLまたは0へのポインタを設定していなかったので、pAdeleteへの最初の呼び出しを、見ることができ、Cによってすでに割り当て解除メモリを解放しようとする試みとして捕まるんでした++私のプラットフォームで実行時。

二重削除の結果は「未定義の動作」なので、実際に何が起こるかは実装とプラットフォームによって決まります。

-lmcheckフラグを指定してコンパイルすることで、glibcメモリ整合性チェッカーとのリンクを使用すると、割り当て/解放メモリのエラーを迅速に検出できる場合があります。

関連する問題