当使用C++异常来传输errno状态时,g ++(4.5.3)为以下代码生成的编译代码
#include <cerrno>
#include <stdexcept>
#include <string>
class oserror : public std::runtime_error {
private:
static std::string errnotostr(int errno_);
public:
explicit oserror(int errno_) :
std::runtime_error(errnotostr(errno_)) {
}
};
void test() {
throw oserror(errno);
}
Run Code Online (Sandbox Code Playgroud)
是出乎意料的(在Linux上,x86_64)
.type _Z4testv, @function
...
movl $16, %edi
call __cxa_allocate_exception
movq %rax, %rbx
movq %rbx, %r12
call __errno_location
movl (%rax), %eax
movl %eax, %esi
movq %r12, %rdi
call _ZN7oserrorC1Ei
Run Code Online (Sandbox Code Playgroud)
这基本上意味着作为C++异常的参数的errno几乎没用,因为在调用__errno_location(这是errno的宏内容)之前调用__cxa_allocate_exception,前者调用std :: malloc而不是保存errno状态(至少据我所知,libstdc ++的eh_alloc.cc中的__cxa_allocate_exception的来源).
这意味着在内存分配失败的情况下,实际传递到异常对象的错误号将被std :: malloc设置的错误号覆盖.的std ::的malloc不保证保存现有错误号状态,无论如何,即使在成功退出的案例 - 所以上面的代码在一般情况下绝对打破.
在Cygwin,x86上,为test()编译(也使用g ++ 4.5.3)的代码是可以的,但是:
.def __Z4testv; .scl 2; …Run Code Online (Sandbox Code Playgroud)