生成されたアセンブリコードを見ると、何が起きているのかが明確になります。次のC++コード:
hDevice = CreateFileA(path, // drive to open
// etc...
);
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
throw runtime_error(error_message());
}
は(少なくともデフォルトの最適化を使用して)アセンブリコードのストレッチを生成します:
call [email protected] #
LEHE4:
sub esp, 28 #,
mov DWORD PTR [ebp-12], eax # hDevice, D.51673
cmp DWORD PTR [ebp-12], -1 # hDevice,
jne L5 #,
mov DWORD PTR [esp], 8 #,
call ___cxa_allocate_exception # // <--- this call is made between the
# // CreateFile() call and the
# // error_message() call
mov ebx, eax # D.50764,
lea eax, [ebp-16] # tmp66,
mov DWORD PTR [esp], eax #, tmp66
LEHB5:
call __Z13error_messagev #
あなたがスローされた例外のためのいくつかのメモリブロックを割り当てるために___cxa_allocate_exception
に行われた呼び出しを参照してください。その関数呼び出しはGetLastError()
状態を変更しています。
C++コードがどのように見える時:
hDevice = CreateFileA(path, // drive to open
// etc...
);
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
const string msg = error_message();
throw runtime_error(msg);
}
その後、あなたは、次の生成されたアセンブリを得る:
error_message()
に失敗した
CreateFile()
コールとコールの間に外部関数を呼び出すことはありません
call [email protected] #
sub esp, 28 #,
mov DWORD PTR [ebp-12], eax # hDevice, D.51674
cmp DWORD PTR [ebp-12], -1 # hDevice,
jne L5 #,
lea eax, [ebp-16] # tmp66,
mov DWORD PTR [esp], eax #, tmp66
call __Z13error_messagev #
LEHE4:
sub esp, 4 #,
mov DWORD PTR [esp], 8 #,
call ___cxa_allocate_exception # // <--- now this happens *after*
// error_message() has been called
。
この種の問題は、GetLastError()
またはerrno
のようなグローバルな状態を使用したエラー処理の主な問題の1つです。
'error_message(GetLastError())'を呼び出すようにコードを変更するとどうなりますか? –
「GetLastError()」、C++のtry/catch例外、Win32「Structured Exception Handling」(SEH)はすべて3つの異なる(関連していますが異なる)ものです。あなたは一般的に1つまたは別のものを使用しますが、お互いに一緒に使用するべきではありません。 – paulsm4
@GregHewgill GetLastError()を非表示にしたいので、代わりにerror_message()を使用したいと思います。 – Ali