Nếu bạn nhìn vào mã lắp ráp được tạo, nó sẽ trở nên rõ ràng những gì đang xảy ra. CáC++ C code sau:
hDevice = CreateFileA(path, // drive to open
// etc...
);
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
throw runtime_error(error_message());
}
Tạo một đoạn mã lắp ráp (ít nhất là sử dụng tối ưu hóa mặc định):
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 #
Bạn thấy một cuộc gọi thực hiện để ___cxa_allocate_exception
phân bổ một số khối bộ nhớ cho các ngoại lệ được ném . Cuộc gọi chức năng đó đang thay đổi trạng thái GetLastError()
.
Khi C++ trông giống như:
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);
}
Sau đó, bạn sẽ có được lắp ráp tạo sau:
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
mà không gọi một chức năng bên ngoài giữa thất bại CreateFile()
cuộc gọi và cuộc gọi đến error_message()
.
Loại sự cố này là một trong những vấn đề chính với xử lý lỗi khi sử dụng một số trạng thái toàn cầu như GetLastError()
hoặc errno
.
Điều gì sẽ xảy ra nếu bạn sửa đổi mã của mình để gọi 'error_message (GetLastError())'? –
Bạn nhận ra, tất nhiên, rằng "GetLastError()", C++ try/catch exception, và Win32 "Structured Exception Handling" (SEH) là tất cả ba thứ khác nhau (liên quan, nhưng khác nhau), phải không? Bạn thường sử dụng một hoặc khác, nhưng bạn * không nên * thường sử dụng chúng * cùng nhau *, kết hợp với nhau. – paulsm4
@GregHewgill Tôi muốn ẩn GetLastError() và tôi muốn sử dụng error_message() thay thế. – Ali