コンストラクタの例外でメモリリーク
コンストラクタは値を返すことができません。そのため、コンストラクタで発生したエラーは、必ず例外として通知することになります。
ところが、Visual C++ 5.0 では、コンストラクタで例外を発生させた時に、メモリリークが発生するというバグがあります。
例えば、下記のようなコンストラクタを作ったとします。
Foo::Foo ( ) {
:
if (エラーが起きたら)
THROW( new MyException() );
:
}
このFooクラスのインスタンスを作る処理は、次のようになります。
Foo* foo = NULL;
try {
foo = new Foo();
// 正常処理
} catch ( MyException* exception ) {
exception->Delete();
// 例外処理
}
if (foo)
delete foo;
このソースコードを Visual C++ 5.0 でビルドして実行すると、メモリリークが発生します。具体的には、生成に失敗したはずのFooクラスのインスタンスが、何故か生成されてしまいます。ところが、変数fooの値はNULLになってしまうため、削除することができません。
Visual C++ 6.0 では、このバグは直されています。
Visaul C++ 5.0 でこの問題を回避するには、下記のように、コンストラクタの中で自分自身を削除するしかありません。
Foo::Foo ( ) {
try {
:
if (エラーが起きたら)
THROW( new MyException() );
:
} catch ( MyException* exception ) {
delete this;
throw;
}
}
もちろん、Visual C++ 6.0 では、このような書き方はアプリケーションエラーとなります。
実数の表示でアプリケーションエラー
下記のソースコードを Visual C++ 5.0 でビルドして実行すると、アプリケーションエラーになります。
double value = 1.0e+160;
CString s;
s.Format("%f", value);
これは、Visual C++ 5.0 のCStringクラスの、FormatV関数にバグがあるためです。
Format関数は、FormatV関数を呼び出しています。FormatV関数では、引数で渡された実数を文字列にした時に、どれくらいの長さになるかを計算して、バッファを確保しています。しかし、この長さの計算が間違っており、値によっては、確保されるバッファのサイズが足りません。その結果、アプリケーションエラーになってしまいます。
Format関数は、プログラムの計算結果をログファイルに書き出す際にも使われることが多いです。プログラムに誤りがあって、変数におかしな値が入った時こそ、ログは出力されなければなりません。しかし、このバグのため、double型変数に不正な値が入っていた時は、ログが出力できません。つまり、肝心な時にログが得られない危険性があります。
Visual C++ 6.0 では、このバグは直されています。