Se si guarda il codice assembly generato, diventa chiaro cosa sta succedendo. Il seguente codice C++:
hDevice = CreateFileA(path, // drive to open
// etc...
);
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
throw runtime_error(error_message());
}
genera un tratto di codice assembly (almeno utilizzando ottimizzazione predefinito):
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 #
Si vede una chiamata fatta a ___cxa_allocate_exception
per allocare qualche blocco di memoria per l'all'eccezione generata . Quella chiamata di funzione sta cambiando lo stato GetLastError()
.
Quando il codice C++ si presenta come:
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);
}
Quindi si ottiene la seguente assembly generato:
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
che non richiede una funzione esterna tra il fallito CreateFile()
chiamata e la chiamata a error_message()
.
Questo tipo di problema è uno dei problemi principali con la gestione degli errori utilizzando uno stato globale come GetLastError()
o errno
.
Cosa succede se modifichi il tuo codice per chiamare 'error_message (GetLastError())'? –
Ti rendi conto, ovviamente, che "GetLastError()", C++ tenta/cattura le eccezioni e Win32 "Structured Exception Handling" (SEH) sono tutte e tre le cose (correlate, ma diverse), vero? Generalmente usi l'uno o l'altro, ma tu * non dovresti * generalmente usarli * insieme *, in combinazione l'uno con l'altro. – paulsm4
@GregHewgill Voglio nascondere GetLastError(), e vorrei invece usare error_message(). – Ali