hSomething = ::CreateSomething(...); |
_Winnie C++ Colorizer |
Ну, о том, что вообще-то имеет смысл сообщать об ошибке в виде кода ошибки, а не в виде невнятной строки (непонятно на каком языке) речь даже не идет. Представим, что нам очень нужно записать куда-нибудь именно строку, т.е. на месте throw std::runtime_error вполне мог бы быть некий LogLog.
Возвращаемся к коду. Если бы я увидел такой код на review, я посчитал бы его некорректным, аргументируя тем, что компилятор вполне может расставить вызовы функций в следующей последовательности:
call std::basic_string<char>::std::basic_string<char>(const char *) |
_Winnie C++ Colorizer |
Не трудно представить, к чему это приведет, учитывая, что конструктор строки вполне может вызвать malloc, а значит и HeapAlloc. (Который пренепременно вызовет SetLastError(NO_ERROR) в случае успешного выделения памяти)
Поэтому, я сам всегда старался писать так, чтобы исключить возможные side effects:
hSomething = ::CreateSomething(...); |
_Winnie C++ Colorizer |
....
До тех пор, пока, совершенно случайно, не наткнулся на тот факт, что утверждение
... HeapAlloc. Который пренепременно вызовет SetLastError(NO_ERROR) в случае успешного выделения памяти.не является истинным.
MSDN утверждает, что HeapAlloc вообще никогда не зовет SetLastError, а HeapReAlloc зовет ее только в случае неудачного выделения памяти. Тестами подтверждается.
Да и вообще, как выяснилось, количество API функций, которые устанавливают SetLastError(NO_ERROR) по поводу и без повода не так уж и велико: сюда входит файловое API, функции работы с ini файлами, с ресурсами, GlobalUnlock/LocalUnlock, и, почему-то, EqualSid(???). Все.
Поэтому, перезатереть значение NtCurrentTeb()->LastErrorValue в нашем случае - некому. Минус одна старая параноидальная привычка (когда-то я таки обжегся на таких сайд эффектах, но код уже и не припомню).
1 comment:
https://connect.microsoft.com/VisualStudio/feedback/details/1775690/calling-operator-new-may-set-lasterror-to-0
Post a Comment