いつも参考にしております。
早速ですが、質問です。
charの2次元配列を生成して、使い終わったら
deleteしているだけなのですが、newした配列の
メモリ解放を行おうとするとデバッグエラーが
出てしまいます。
以下のソースではエラーになるため、配列の解放を
コメントアウトしていますが、これではメモリリーク
してしまいます。
ちなみに他の型(intやlong)では、以下のソースで
エラーは発生しません。
申し訳ありませんが、原因と対策をお教えください。
お願いいたします。
環境
・WinXP Home
・VC++ .net2003
// main の引数を動的配列にコピーし、
// 解放するだけのプログラム
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
New objNew;
objNew.CopyArg(argc, argv);
objNew.DeleteArg();
return 0;
}
int New::CopyArg(int argc, TCHAR** argv)
{
m_pszArgv = NULL;
m_iArgc = argc;
m_pszArgv = new TCHAR* [ m_iArgc ];
for( int i = 0 ; i < m_iArgc ; i++ ) {
size_t tLen = _tcslen( argv[i] );
m_pszArgv[i] = new TCHAR [ tLen ] ;
_tcscpy(m_pszArgv[i], argv[i]);
printf(m_pszArgv[%d] = %s\n, i, m_pszArgv[i]);
}
return 0;
}
int New::DeleteArg(void)
{
// メモリ解放
for( int i=0; i<m_iArgc; i++ ){
//delete [] m_pszArgv[i]; // →エラーになるのでコメント
// メモリリークしてしまう!
}
delete [] m_pszArgv;
return 0;
}
> size_t tLen = _tcslen( argv[i] );
は文字列の終端である '\0' の領域を含んでいませんので、
size_t tLen = _tcslen( argv[ i ] ) + sizeof( TCHAR );
としてあげましょう。
> size_t tLen = _tcslen( argv[ i ] ) + sizeof( TCHAR );
> としてあげましょう。
tLen は文字数単位なんだから、+1 でいいんじゃない?
> tLen は文字数単位なんだから、+1 でいいんじゃない?
ああ、そうでした orz
size_t tLen = _tcslen( argv[ i ] ) + 1;
です。
すいませんでした。+指摘ありがとうございました。
ちなみに
_tcsdup
http://www.microsoft.com/JAPAN/developer/library/vccore/_crt__strdup.2c_._wcsdu
p.2c_._mbsdup.htm
ってな便利な関数があります。
ただし、
> _strdup 関数は malloc 関数を使って string のコピー用の記憶領域を割り当てま
す。
> したがって、必ず _strdup が返したポインタを引数として free ルーチンを呼び出し
て、
> メモリを解放してください。
です。
# std::vector<std::string>とかの方が面倒がないような...用途次第ですが。
> 用途次第ですが
TCHAR前提だと、ちょっとめんどくさそうかも。
std::basic_string< TCHAR >とか?
std::stringとstd::wstringの切り分けのうまい方法あるんでしょうか>詳しい方
namespace win32
{
typedef std::basic_string<TCHAR> string;
}
win32::string str;
みたいなのでどうでしょう。
実際、似たようなのを使ったことありますが、
namespace foo = win32;
foo::string str2;
みたいなこともできるはず。
# グローバルで using namespace std; とか書いてる駄目なソースだとちょっと厄介/面倒かも。
namespace win32 {
typedef std::basic_string<TCHAR> string;
}
int _tmain(int argc, TCHAR* argv[]) {
std::vector<win32::string> args(argv, argv+argc);
...
…ってことで。
ご回答ありがとうございます。
メモリリークを検出できるという点で、new
を使用したいと思います。
size_t tLen = _tcslen( argv[ i ] ) + 1;
で問題ないことを確認しました。
STLでも有益な情報ありがとうございます。
これからじっくり試してみようと思います。
みなさん今後ともよろしくお願いします。
無理にとめる権利はないのですが、少しだけ。
> メモリリークを検出できるという点で、newを使用したいと思います。
std::vector<win32::string> args(argv, argv+argc);なら、
new のようにプログラマがわざわざメモリリークを意識しなくても、
内部で勝手に管理してくれるので、普通に使ってるだけでそうそうリークしませんし、
仮にリークしたらデバッグモードで通知されることにも変わりないと思うのですが、
new を使う利点として、上記をあげられている根拠がよくわからないです。
> メモリリークを検出できるという点で、new
> を使用したいと思います。
...わかんね orz
メモリリークを心配しなくて済む方が良いに決まってんじゃん。
ま、malloc() 使うよっか、new の方が、デバッガがリーク個所を教えてくれるから
良いにしても、可能なら、STLの方が安上がりですね。
わけわかんないですか、どうもすいません。
> メモリリークを検出できるという点で、new
> を使用したいと思います。
strdup ~ free より new のほうがメモリリーク・・・
という意味です。
> STLでも有益な情報ありがとうございます。
> これからじっくり試してみようと思います。
std::vector<win32::string> args(argv, argv+argc);
のほうがいいんでしょうが、STLもテンプレートも使った
ことがないので、今勉強中です。
わからなければまた質問させていただきますので
よろしくお願いします。
> strdup ~ free より new のほうがメモリリーク・・・
> という意味です。
そういうことならまだわからなくもないですが、
デバッグでメモリリークが検出されるのはどちらでも多分変わらないです。
とはいえ、CならまだしもC++でduplicate使う意味はほぼないですから、
これを気に std::string とか使ってみるのも面白いかと。
# あまりの便利さにC言語には戻れなくなってしまうかもしれませんが(笑