奈良県でソフトウェア開発・Webサイトの運営をしているフリーランスのエンジニアです

ロジカルアーツ研究所

C++Builder

C++Builder XE3 64bitコンパイラで___finallyブロックが実行されない

投稿日:2013年11月12日 更新日:

C++BuilderではC++標準のtry~catch構文に加えて、try~__finally構文が拡張仕様としてサポートされています。これはメモリ解放など例外の有無にかかわらず必ず実行させたい処理がある場合に大変便利で重宝してきました。

ところが64bitコンパイラを導入してから、この__finallyブロックが期待通りに動作していないことが発覚し、大変困っています。簡単なテストとして、下のコードを作ってみました。

void __fastcall TForm1::FormCreate(TObject *Sender)
{
	try {
		try {
			int a = StrToInt("abc");
		} catch (Exception &e) {
			ShowMessage(e.Message);
			return;
		}
	} __finally {
		ShowMessage("必ず実行される処理");
	}
}

見ておわかりの通り、"abc"は整数ではありませんので必ずEConvertErrorクラスの例外が発生するようになっています。したがって期待される動作としては、まず「"abc" は整数ではありません」の例外メッセージが表示された後、「必ず実行される処理」のメッセージが表示されるはずです。なぜなら__finallyブロックはreturn文より先に必ず実行されるからです。


このコードは従来の32bitコンパイラであれば期待通りに動作しました。ところが64bitコンパイラでは「必ず実行される処理」が表示されないのです。つまり__finallyブロックが実行されていないことになります。

C++ではtryでも__tryでもどちらでもよいことになっていますが、試しに__try~__finallyに置き換えてみても結果は同じでした。また"abc"を"000"に書き換えてみると、今度は「必ず実行される処理」が表示されました。したがって、__finallyブロックがまったく実行されないというわけではなく、return文よりも先に実行されないというのが正しいようです。

ネットで調べてみましたが、今のところ原因や解決方法は見つかっていません。ですから仕方なくtry~__finallyブロックを外してreturn文の前にすべて終了処理を置きました。非常にエレガントではない方法ですが、現状ではそうするしかないのです。しかしtry~__finallyブロックを多用してしまっているプロジェクトもあるので、今から全部書き直すとなると大変です。

もしかするとこれはXE3 64bitコンパイラ特有のバグなのでしょうか? もし何か情報をお持ちでしたらコメント下されば幸いです。

(12/11追記)
上記の問題はまだ解決していませんが、終了処理はCの言語仕様であるgoto文を使用することによって対処しています。構造化プログラミングの観点からは絶対使ってはいけないような印象を持たれているgoto文ですが、ちゃんと理解して使うのは何の問題もありません。goto文を使うことによって終了処理が非常に簡潔に、エレガントに記述できます。

-C++Builder

Copyright© ロジカルアーツ研究所 , 2024 All Rights Reserved Powered by STINGER.