とっちゃん's Blog

WindowsInstaller に WiX はいかがですか~

目次

Blog 利用状況

ニュース

とっちゃんって?

コミュニティ

@ITの記事

CodeZineの記事

WiX チュートリアル

Windows ユーザー エクスペリエンス ガイドライン

唯一の日本語書籍

記事カテゴリ

書庫

日記カテゴリ

インストーラ関連

旧館

メモリーリークしないのか!

ネタ元:コンストラクタで例外はありか?のコメントより

 

試してみました。環境はVS2010。ほかに手元にないしね。

まずは、前回のものを動くやつにしたもの。

#include <crtdbg.h>
#include <exception>
class A
{
public:
  A( bool exp )
    : value( exp )
  {
    throw std::exception();
  }
  ~A()
  {
  }
public:
  bool value;
};

int _tmain(int argc, _TCHAR* argv[])
{
  _CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG )|_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF );
  A* a = nullptr;
  try{
    a = new A( true );
  }
  catch(...)
  {
  }
  delete a;
  return 0;
}

例外はもちろん発生しますが、メモリーリークは発生せず、きちんと解放されていました。

複数階層も試してみました。

#include <crtdbg.h>
#include <exception>

class B
{
public:
  B( bool exp )
    : val( exp )
  {
    throw std::exception();
  }
public:
  bool val;
};

class A
{
public:
  A( bool exp )
    : value( nullptr )
  {
    value = new B( exp );
  }
  ~A()
  {
    delete value;
  }
public:
  B* value;
};

int _tmain(int argc, _TCHAR* argv[])
{
  _CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG )|_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF );
  A* a = nullptr;
  try{
    a = new A( true );
  }
  catch(...)
  {
  }
  delete a;
  return 0;
}

A,Bともにメモリーリークせずに解放されます。

おそらく一番ありがちじゃないかな?と思いますが。。。

#include <crtdbg.h>
#include <exception>

class B
{
public:
  B( bool exp )
    : val( exp )
  {
  }
public:
  bool val;
};

class A
{
public:
  A( bool exp )
    : value( nullptr )
  {
    value = new B( exp );
    if( exp ){
      throw std::exception();
    }
  }
  ~A()
  {
    delete value;
  }
public:
  B* value;
};

int _tmain(int argc, _TCHAR* argv[])
{
  _CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG )|_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF );
  A* a = nullptr;
  try{
    a = new A( true );
  }
  catch(...)
  {
  }
  delete a;
  return 0;
}

こちらは、メモリーリークしました。Bだけですけど。まぁメモリアロケート後の例外ですからね。そりゃトラップするほうが無理ってもんです。。。

投稿日時 : 2011年2月20日 15:37

コメントを追加

# re: メモリーリークしないのか! 2011/02/20 15:58 デフォルトの名無しさん

最後のケースでも B* value を std::auto_ptr<B> value などとすればよい
です。これによりコピーコンストラクタや代入演算子をデフォルトで済ませても
致命的な問題を避けられるようにもなります。

# re: メモリーリークしないのか! 2011/02/20 18:15 とっちゃん

ほんとだ。 auto_ptr にすれば避けられますね。ふむふむ。

でも必ずしも使える。。。というわけじゃないのがきついところだなぁ。。。

ここでは、検出が楽なのでメモリ操作で試してますが、リークするのはメモリだけじゃないですからね。API呼び出しが絡んでくると厳しい場合も出てきそうです。

でも、そういうことするとコンストラクタが太るだけなので、普通はやらないんでしょうけどw

# re: メモリーリークしないのか! 2011/02/20 18:47 デフォルトの名無しさん

std::auto_ptr が使えないというのはどんな場合のことでしょうか?
メモリ以外についても RAII に沿ったクラスで対応すれば同じことになります。

↓のコメント欄にも同様のやりとりがありますので参考にしてください。
http://www.kijineko.co.jp/tech/superstitions/dont-throw-exception-from-constructor.html

# re: メモリーリークしないのか! 2011/02/20 21:21 とっちゃん

RAIIに沿ったクラスになっているものばかりとは限りませんし。
使い手は必ずしもC++のエキスパートというわけでもないですし。

とはいえ、new A() でAのコンストラクタが例外を吐き出してもAのために確保したメモリは安全に解放されるというのが分かっただけで、おいら的にはこれについては問題解決です。

解放されないパターンも分かったし(その理由や、回避策も)

Blogの記事にした甲斐がある。

タイトル
名前
URL
コメント