2012-04-10 9 views
9

スマートポインタの世界は初めてです。私は読んだことがあり、スマートポインタは例外が発生した後にプログラムが終了してもメモリがリークするのを避けると述べています。スマートポインタを使用しても例外でC++のリークが発生する

私はこれを試してみるための簡単なプログラムを書きましたが、Valgrindは私のプログラムがメモリを漏らしていると教えています(3つのallocsと1つだけfree)。

#include <iostream> 
#include <memory> 

using namespace std; 

int main() 
{ 
    auto_ptr<int> ptr_int(new int(5)); 

    throw std::bad_alloc(); 

    cout << *ptr_int; 
} 

そして、このValgrindのレポート:

これは、ソースコードがある

==27862== Memcheck, a memory error detector 
==27862== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. 
==27862== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info 
==27862== Command: ./smart_pointers 
==27862== Parent PID: 5388 
==27862== 
==27862== 
==27862== HEAP SUMMARY: 
==27862==  in use at exit: 104 bytes in 2 blocks 
==27862== total heap usage: 3 allocs, 1 frees, 120 bytes allocated 
==27862== 
==27862== 4 bytes in 1 blocks are still reachable in loss record 1 of 2 
==27862== at 0x4026351: operator new(unsigned int) (vg_replace_malloc.c:255) 
==27862== by 0x804878A: main (smart_pointers.cpp:8) 
==27862== 
==27862== 100 bytes in 1 blocks are possibly lost in loss record 2 of 2 
==27862== at 0x4025BD3: malloc (vg_replace_malloc.c:236) 
==27862== by 0x40E861A: __cxa_allocate_exception (in /usr/lib/libstdc++.so.6.0.14) 
==27862== by 0x80487AE: main (smart_pointers.cpp:10) 
==27862== 
==27862== LEAK SUMMARY: 
==27862== definitely lost: 0 bytes in 0 blocks 
==27862== indirectly lost: 0 bytes in 0 blocks 
==27862==  possibly lost: 100 bytes in 1 blocks 
==27862== still reachable: 4 bytes in 1 blocks 
==27862==   suppressed: 0 bytes in 0 blocks 
==27862== 
==27862== For counts of detected and suppressed errors, rerun with: -v 
==27862== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 19 from 8) 

スマートポインタは、割り当てられたリソースは、例外が現れた場合でも破壊されることを保証使用していますか?

+4

それは '()'そのデフォルトの動作(中止 '呼び出すことですが)'終了呼び出して終了だから、まったく例外をキャッチしていません。あなたが例外をキャッチするとどうなりますか? –

+0

最新のOSを使用している場合、OSは終了時にプログラムが使用していたメモリを再利用します。そのため、メモリ自体が漏れてしまう心配はありません。もちろん、明示的に自分自身をクリーンアップする必要のあるリソースを使用している場合は、別の状況です。 – TheJuice

答えて

5

、およびメモリなどのあなたは、そのスタックに割り当てられましたスマートポインタによって管理されているにもかかわらず、フレームリークが発生します。 std::bad_allocmain()にキャッチして正常に戻ると、スマートポインタがその役割を果たします。

+0

その文を "スマートポインタは_handled_ execptionsの場合でもメモリリークを避ける"に変更します。あなたは例外を処理していません。 – modelnine

+0

foo()にコードを移動すると、例外をキャッチしないと助けになりません。例外をキャッチしないと、アプリケーションは終了し、デストラクタは呼び出されません(この場合、OSはすべてのメモリを自動的に再利用します)。これを使用してください:{ \t \t foo(); \t}キャッチ(STD :: bad_alloc EX) \t { \t} その後、あなたはメモリが正しく – skimon

+2

を割り当て解除、私はそれを実装までだったC++で、元々は約C++ 11を知らないが表示されるはずですデストラクタが未処理の例外で呼び出されたかどうか。要点:いくつかのデストラクタはメモリを再利用する以上のことをしている(例えば、サーバ接続をきれいにシャットダウンしたり、一時ファイルを削除するなど)。したがって、この場合でもデストラクタを呼び出すことは理にかなっていると主張することができます。しかし、 'main'にcatch-allを追加するのは簡単で、スタックを解くことは簡単ではないので、スタックがデバッグに役立つことは義務付けられていません。私は、キャッチされていない例外のスタックを巻き戻す実装があるかどうかはわかりません。 – celtschk

12

例外が処理されない場合は、std::terminateを呼び出す前にスタックが解消されるかどうかは実装定義です。

例外を処理する場合、スマートポインタは期待どおりに動作します。

参考:いくつかの状況の例外処理で

C++ 11 15.5.1 std::terminate()関数は以下の微妙なエラー処理技法のために放棄されなければなりません。これらの状況は以下のとおりです。

........

- 例外処理メカニズムがスローされた例外のハンドラを見つけることができない、または

........

2この場合、std::terminate()が呼び出されます。 一致するハンドラが見つからない状況では、std::terminate()と呼ばれる前にスタックが巻き戻されるかどうかは実装定義されます。

、通常のクリーンアップは、(少なくとも main()のスタック・フレームのために)実行されません(キャッチされない例外の場合のように) std::terminate()が呼び出される
+0

私は標準参照を追加する自由を取った、あなたがそれを気にしないことを願っています。 –

2

例外がキャッチされない場合、スタックアンワインドは実装固有のものです。したがって、あなたのケースでは、メモリを解放しません。

また、auto_ptrはもはや推奨されません。

使用のstd :: unique_ptrを:

unique_ptr<int> ptr_int(new int(5)); 
+0

ありがとうございます。私はunique_ptrを知っています。 – efabor

+0

メイン()をきれいにするにはコードをfoo()に移動しましたが、それでも同じ問題です。私は例外が管理されていない場合、スマートポインタは役に立たないと思います。しかし、全てのリーディングIVは、彼らがstd名前空間を使用して の#include の#include 「スマートポインタもexecptionsの場合にメモリリークを避けるだろう」述べ行わ; void foo() { \t auto_ptr ptr_int(new int(5)); \t throw std :: bad_alloc(); \t cout << * ptr_int; } int main() { \t foo(); \t cout << "END"; } – efabor

+0

読書について:例外はあなたのプロセスを終了させ、そしてすべてのメモリはとにかく解放されます。あなたはリソースリーク以上の未知の例外について心配する必要があります。名前空間stdを使用して 'の#include の#include 。 int func() { \t unique_ptr ptr_int(新しいint(5)); \t throw std :: bad_alloc(); \t cout << * ptr_int; \t return 0;メイン } INT(){ \tが\t { \t \t FUNC()を試みます。 \t} \tキャッチ(...) \t {\t \t COUT <<「キャッチ全てにおいて..."<< endl; \t} \t } 上記のコードはメモリを問題なくリリースしています。 – Ram

関連する問題