[C++]newの例外

[戻る]
reshia 2005/03/20(日) 12:14:35
以下のようなプログラムで、
//--------------------------------
char* data;
try {
    data = new char[0xfffffffe];
} catch (bad_alloc e) {
    //delete[] data; // 必要?
    exit(-1);
}
//--------------------------------
(1)try節のnewでメモリ確保が失敗して例外が投げられた場合、
  catch節で、deleteする必要ってありますか?
(2)VC++7.1では、newがbad_allocの例外を投げないらしいので、
  _set_new_handler(ThrowBadAlloc)しているにもかかわらず、
  int ThrowBadAlloc(size_t)関数に処理が渡らずに、異常終了してしまいます。
(3)コンパイラがVCかどうかを調べる方法ありますか?

以上、よろしくお願いします。

Ban 2005/03/20(日) 13:06:58
(1) 確保に失敗しているから std::bad_alloc が投げられるので、解放は不要です。
やってはいけません。

# もしも、この時の data が NULL になっている処理系なら(言語的な保証はない)、
# delete NULL は安全なことが言語規格で保証されてますので単に無駄な処理。
# data の値が不定な処理系では、不正な delete になります。


(2) VC7.1 は規格どおりに正しく std::bad_alloc を投げます。
よって、_set_new_handler は不要です。

# VC6.0 は規格制定前の古い実装なので、そういう小細工をしないと
# std::bad_alloc を投げてくれません。

VC7.1 でハンドラに処理がわたらない理由はよく分かりませんが....。


(3) VC は、_MSC_VER という名前のマクロを定義します。
普通、主要な別のコンパイラはこのマクロを定義しません。

よってこのマクロを defined() で調べればプリプロセッサ上で判定可能です。

# _MSC_VER の値は、VC のバージョンを表します。詳細は MSDN 参照。



> } catch (bad_alloc e) {
catch(std::bad_alloc& e) // 参照で受けることをお勧めします。

reshia 2005/03/20(日) 13:22:39
なるほど。
(1)(3)に関してはわかりました。
(2)は、うまくいきません。

一応、Debug/Release両モードでやりましたが、駄目でした。catchできません。
Release時には、wincore.cppのAfxCallWndProcという関数に処理が渡っていき、
「out of memory」のメッセージが出力され、
プログラム自体も落ちないのですが気持ち悪いです。
それに、Debug時にはプログラムが落ちてしまうのも嫌ですし。

>catch(std::bad_alloc& e) // 参照で受けることをお勧めします。
ありがとうございます。そうします。

reshia 2005/03/20(日) 13:23:35
あ、MFC使ってます。
すみません。

uid 2005/03/20(日) 13:33:48
MFCの場合はCMemoryException*がスローされます。
MFCの例外処理は決まりがあるのでMSDNをよく読んでください。

reshia 2005/03/20(日) 13:44:33
[[解決]]
ありがとうございます。
できました。

//--------------------------------
char* data;
try {
    data = new char[0xfffffffe];
}
#ifdef _MSC_VER
catch (CMemoryException* e) {
    exit(-1);
}
#endif
//--------------------------------

Ban 2005/03/20(日) 17:41:44
exit するなら実害は少ないでしょうが、MFC の例外は TRY-CATCH 系
マクロを使わない限り、自前で解放してあげる必要があるかと。

 e->Delete();

Ban 2005/03/20(日) 22:55:30
# 蛇足ですが、
# _MSC_VER だけでは、MFC を使っているかどうか判定できません。
# VC7.1 でも MFC を使わない場合は std::bad_alloc の方が飛んできますので、
# (そのコードが完全に MFC に依存していて単体では使えない場合を除き)
# CMemoryException に続けて std::bad_alloc も catch しておいた方が
# いいかもしれません。

reshia 2005/03/20(日) 23:50:23
Banさん、追記ありがとうございます。

> マクロを使わない限り、自前で解放してあげる必要があるかと。
msdnに、そう書いてありましたので、解放しました。

> _MSC_VER だけでは、MFC を使っているかどうか判定できません。
私もそう思ったので、std::bad_allocもcatchしておきました。
何か方法はありそうな気もしますが・・・。

遅くなって、もうしわけありませんでした。

古いスレッドには追加発言できません。