在标准库中,异常类的构造函数的参数类型,如std::runtime_error
,遵循以下模式:
runtime_error( const std::string& what_arg ); // (1)
runtime_error( const char* what_arg ); // (2)
runtime_error( const runtime_error& other ); // (3)
令我感到困惑的是,使用 (1)const std::string&
代替了std::string
,这显然会导致构造函数内部出现额外的复制操作。
如果参数类型是std::string
,不仅可以避免额外的复制操作,而且也是noexcept
;这是我最近意识到的一个结论:
如果标记为的函数noexcept
在其构造期间具有可能引发异常类型的参数,那么即使保证会引发异常,也不会导致程序因异常而终止。
测试程序已证实了这一点。
那么,为什么标准库异常构造函数参数列表不使用std::string
?或者我的理解和结论以及测试程序是错误的,甚至是未定义的行为?
我认为您假设它
std::runtime_error
是用std::string
成员变量来实现的,用于存储what()
。事实并非如此,例如libstdc++ 有一个特殊__cow_string
成员类型,libc++ 使用特殊std::__libcpp_refstring
成员类型,MSVC 使用__std_exception_data
类型。std::string
对于没有成员的实现,使用按值获取的重载实际上会引入额外的副本std::string
(一个副本到临时文件std::string
,另一个副本到内部格式)。r 值引用重载至少不会比引用有缺点,const
但我想自从 c++11 中添加 r 值以来,没有人认为这值得标准化(大概是因为没有实现真正使用std::string
成员)。为了避免您提到的问题,通常不使用
std::string
成员来实现异常,创建异常时分配可能会失败(特别是由于内存耗尽而引发异常),因此通常会使用一些专门的分配器,即使没有可用的通用堆空间也不会失败。