none
メモリーリークが発生する RRS feed

  • 質問

  • C++の勉強を始めたばかりで何が原因で以下のような現象が発生するのかまた、どう対処してよいのかわかりません。お力をお貸しください。

    処理内容は.iniファイルからの読み込みです。プログラム終了後に出力ウィンドウに次のようなメッセージが表示されます。

    Detected memory leaks!
    Dumping objects ->
    .\Test_01Dlg.cpp(151) : {127} normal block at 0x003BA078, 512 bytes long.
     Data: <D : \ 2 C G L \ > 44 00 3A 00 5C 00 32 00 43 00 47 00 4C 00 5C 00
    .\Test_01Dlg.cpp(151) : {124} normal block at 0x003B9DE0, 512 bytes long.
     Data: <3 0             > 33 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00
    .\Test_01Dlg.cpp(151) : {122} normal block at 0x003B9BA0, 512 bytes long.
     Data: <1 9 2 . 1 6 8 . > 31 00 39 00 32 00 2E 00 31 00 36 00 38 00 2E 00
    .\Test_01Dlg.cpp(52) : {119} normal block at 0x003B98B0, 512 bytes long.
     Data: <c : \ V C + + \ > 63 00 3A 00 5C 00 56 00 43 00 2B 00 2B 00 5C 00
    .\Test_01Dlg.cpp(50) : {118} normal block at 0x003B9670, 512 bytes long.
     Data: <D : \ 2 C G L \ > 44 00 3A 00 5C 00 32 00 43 00 47 00 4C 00 5C 00
    Object dump complete.
    プログラム '[5012] Test_01.exe: ネイティブ' はコード 0 (0x0) で終了しました。

    指示された行番号を見ると、
     50:LPTSTR  lpResult = new TCHAR[256];
      52:LPWSTR  lpPathName = new TCHAR[256];
     151:LPTSTR lpTemp = new TCHAR[0x100];
    です。

    たぶんこれらの変数に値を代入したときに発生していると思われますが不明です。

    以上、よろしくお願いいたします。。
    2009年4月24日 5:25

回答

  • new した配列を delete[] してないんじゃないですか?
    // 要素数固定の 256 程度なら静的配列でも十分な気がしますが。

    それから、TCHAR[] を LPWSTR に入れるのは避けるべきです。TCHAR が wchar_t とは限りません。
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 5:58
  • textってなに?
    iniファイルのフルパスとは?

    実行ファイルと同じ位置にあるiniファイルであれば、GetcurrentDirectoryから組み立てるのは間違っています。
    GetModuleFileNameをつかって、実行ファイル名から取得するようにしましょう。

    パスの組み立ては、makepath系もしくはPath~系を使うと便利です。

    参考
    http://social.msdn.microsoft.com/forums/ja-JP/vcgeneralja/thread/37bb536c-d1df-44e5-ae07-9976bf74faf9/

    わんくま同盟[http://blogs.wankuma.com/blue/]
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 7:11
  • また、「それから、TCHAR[] を LPWSTR に入れるのは避けるべきです。TCHAR が wchar_t とは限りません。」
    ですが、今回下記のようなコードでiniファイルのフルパスを与えるために行っていますが、ほかによい方法がございますでしょうか。
    ダイナミックに論点か変更されているんですが。
    質問の方は蒼の洞窟さんのを参照してもらうとして、私が言いたいのは LPWSTR と TCHAR は互換性の無い(かも知れない)型であるってこと。50 行目や 151 行目では TCHAR 配列を LPWSTR 型じゃない変数に代入してますよね?
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 7:59
  • deleteし忘れを防ぐためにも変数を別の用途に再利用すべきではありません。
    Hongliangさんがアドバイスしていますが、

    TCHAR result[256];
    WCHAR pathName[256];
    TCHAR temp[0x100];

    のように配列にすれば解放漏れも防げます。加えて型宣言の誤り(=の左右出方が異なる)も防げます。
    ただし配列で多くのメモリ確保をしてしまうとスタックが枯渇することがあるため注意が必要です。
    これに対してVisual Studio 2008 SP1以降ではヒープを使う方法が提供されています。

    #include <array>
    std::tr1::array<TCHAR, 256> lpResult;

    もしくはVisual Studioのバージョンに依存しない別の方法として

    #include <vector>
    std::vector<TCHAR> lpResult( 256 );

    とすることもできます。どちらもnewしていませんのでdeleteは必要ありません。
    lpResultの型がLPTSTRではなくなりますので、 &lpResult[0] を使用する必要があるかもしれません。
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 9:54
  • 私が言いたいのは LPWSTR と TCHAR は互換性の無い(かも知れない)型であるってこと。
    ちょっと追記と言うことで参考までに。

    TCHARはプロジェクトのプロパティの全般設定にある文字セットによって、変化します。
    (_UNICODEプリプロセッサ定数の定義の有無)

    マルチバイト文字セットの場合にはTCHAR型がchar型のtypedefとなり、Unicode文字セットの場合にはTCHAR型がwchar_t型のtypedefになります。
    LPWSTR型は実際にはwchar_t*型のtypedefになりますので、Unicode文字セットではTCHAR型で互換性がありますが、マルチバイト文字セットでは互換性がありません。

    TCHAR型で確保したのであればLPTSTRあたりを使うべきですし、wchar_t( = WCHAR)型で良いのであれば、LPWSTR型とwchar_t(WCHAR)型を使うべきかと思います。


    関連(文字型、そのポインタ、constのついたポインタ)
    TCHAR, LPTSTR, LPCTSTR
    WCHAR( = wchar_t), LPWSTR, LPCWSTR
    CHAR( = char), LPSTR, LPCSTR
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 14:51
    モデレータ

すべての返信

  • new した配列を delete[] してないんじゃないですか?
    // 要素数固定の 256 程度なら静的配列でも十分な気がしますが。

    それから、TCHAR[] を LPWSTR に入れるのは避けるべきです。TCHAR が wchar_t とは限りません。
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 5:58
  • Hongliangさん、ありがとうございました。
    言われるようにdeleteとすると、発生しなくなりました。

    また、「それから、TCHAR[] を LPWSTR に入れるのは避けるべきです。TCHAR が wchar_t とは限りません。」
    ですが、今回下記のようなコードでiniファイルのフルパスを与えるために行っていますが、ほかによい方法がございますでしょうか。

     nRet = GetCurrentDirectory(0x100,lpPathName);
     lpFileName = lpPathName ;
     text = lpPathName;
     text += _T("\\DATA\\iniFile\\Config.ini");
     lpFileName = text;

    です。

    以上、よろしくお願いいたします。
    2009年4月24日 6:40
  • textってなに?
    iniファイルのフルパスとは?

    実行ファイルと同じ位置にあるiniファイルであれば、GetcurrentDirectoryから組み立てるのは間違っています。
    GetModuleFileNameをつかって、実行ファイル名から取得するようにしましょう。

    パスの組み立ては、makepath系もしくはPath~系を使うと便利です。

    参考
    http://social.msdn.microsoft.com/forums/ja-JP/vcgeneralja/thread/37bb536c-d1df-44e5-ae07-9976bf74faf9/

    わんくま同盟[http://blogs.wankuma.com/blue/]
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 7:11
  • また、「それから、TCHAR[] を LPWSTR に入れるのは避けるべきです。TCHAR が wchar_t とは限りません。」
    ですが、今回下記のようなコードでiniファイルのフルパスを与えるために行っていますが、ほかによい方法がございますでしょうか。
    ダイナミックに論点か変更されているんですが。
    質問の方は蒼の洞窟さんのを参照してもらうとして、私が言いたいのは LPWSTR と TCHAR は互換性の無い(かも知れない)型であるってこと。50 行目や 151 行目では TCHAR 配列を LPWSTR 型じゃない変数に代入してますよね?
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 7:59
  • deleteし忘れを防ぐためにも変数を別の用途に再利用すべきではありません。
    Hongliangさんがアドバイスしていますが、

    TCHAR result[256];
    WCHAR pathName[256];
    TCHAR temp[0x100];

    のように配列にすれば解放漏れも防げます。加えて型宣言の誤り(=の左右出方が異なる)も防げます。
    ただし配列で多くのメモリ確保をしてしまうとスタックが枯渇することがあるため注意が必要です。
    これに対してVisual Studio 2008 SP1以降ではヒープを使う方法が提供されています。

    #include <array>
    std::tr1::array<TCHAR, 256> lpResult;

    もしくはVisual Studioのバージョンに依存しない別の方法として

    #include <vector>
    std::vector<TCHAR> lpResult( 256 );

    とすることもできます。どちらもnewしていませんのでdeleteは必要ありません。
    lpResultの型がLPTSTRではなくなりますので、 &lpResult[0] を使用する必要があるかもしれません。
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 9:54
  • 私が言いたいのは LPWSTR と TCHAR は互換性の無い(かも知れない)型であるってこと。
    ちょっと追記と言うことで参考までに。

    TCHARはプロジェクトのプロパティの全般設定にある文字セットによって、変化します。
    (_UNICODEプリプロセッサ定数の定義の有無)

    マルチバイト文字セットの場合にはTCHAR型がchar型のtypedefとなり、Unicode文字セットの場合にはTCHAR型がwchar_t型のtypedefになります。
    LPWSTR型は実際にはwchar_t*型のtypedefになりますので、Unicode文字セットではTCHAR型で互換性がありますが、マルチバイト文字セットでは互換性がありません。

    TCHAR型で確保したのであればLPTSTRあたりを使うべきですし、wchar_t( = WCHAR)型で良いのであれば、LPWSTR型とwchar_t(WCHAR)型を使うべきかと思います。


    関連(文字型、そのポインタ、constのついたポインタ)
    TCHAR, LPTSTR, LPCTSTR
    WCHAR( = wchar_t), LPWSTR, LPCWSTR
    CHAR( = char), LPSTR, LPCSTR
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    • 回答としてマーク sk7474 2009年5月7日 9:45
    2009年4月24日 14:51
    モデレータ
  • ご回答くださった皆様、ありがとうございます。

    2009年4月26日 23:27
  • こんにちは。中川俊輔です。

    皆様、詳細な回答、アドバイスをありがとうございます。

    B_Wolfさん、フォーラムのご利用ありがとうございます。
    勝手ながら、有用な情報と思われる回答へ回答マークをつけさせていただきました。

    今後ともフォーラムをよろしくお願いします。
    それでは!
    マイクロソフト株式会社 フォーラム オペレータ 中川 俊輔
    2009年5月7日 9:47