Visual Studio(Dinkumware?)使用std::exception
包含内部存储†的消息的实现。(完成一个接受字符串的非标准构造函数。)
因此,实际上不需要虚拟调度来获取错误消息,它可以在任何切片中存活。
更正统的实现确实会打印通用异常消息,因为派生对象被切掉了。(实际上,MS 已经取得了std::exception
和std::runtime_error
等价的效果。这没有什么问题,因为 的返回值std::exception::what
是实现定义的,但它解释了您的结果。)
†这里的内部存储使用松散。它没有内部缓冲区,但有 aconst char*
和 a bool
。const char*
指向消息( 的返回值)what()
,bool
是确定是否应删除缓冲区的标志。
就像这样:
class msvc_exception // for exposition
{
public:
msvc_exception(const char* msg) :
mMsg(msg),
mDoDelete(false)
{}
msvc_exception(const std::string& msg) :
mMsg(copy_string(msg)),
mDoDelete(true)
{}
virtual ~msvc_exception()
{
if (mDoDelete)
delete [] mMsg;
}
virtual const char* what() const throw()
{
return mMsg ? mMsg : "unknown";
}
private:
const char* copy_string(const std::string& str)
{
const char* result = new char[str.size() + 1];
std::copy(str.begin(), str.end(), result);
result[str.size()] = 0; // null-terminate
return result;
}
};
你现在看到它bad_alloc
是这样工作的:
class msvc_bad_alloc : // for exposition
public msvc_exception
{
public:
msvc_bad_alloc() :
msvc_exception("bad_alloc") // note: a static string, no dynamic storage
{}
};
切片不会影响消息,因为消息“存在”在基类中。
其他编译器,如 GCC 和 LLVM,实现起来更直接:
class orthodox_exception
{
public:
orthodox_exception(){}
virtual ~orthodox_exception() {}
virtual const char* what() const throw()
{
return "orthodox_exception";
}
};
class orthodox_bad_alloc :
public orthodox_exception
{
public:
const char* what() const throw()
{
return "orthodox_bad_alloc";
}
};
在这里,切片会影响你的结果。(也就是说,毕竟:总是通过引用来捕捉。)