2015 年更新:
然而,std::runtime_error
接受 astd::string
作为它的参数,这表明它在std::string
某处存储 a。因此,必须在某处进行分配或复制构造。而对于std::string
,这不是一个noexcept
操作。
runtime_error
(and logic_error
) 只需要接受类型为 的参数std::string const &
。他们不需要复制它。
使用这些重载需要您自担风险。LLVM libc++ 不提供存储。
另一方面,GNU libstdc++ 小心翼翼地避免内存不足。它复制字符串的内容,但复制到异常存储空间,而不是新的std::string
.
即使这样,它也会增加一个std::string&&
重载并使用friend
ship 来采用由 rvalue 传递的参数的内部缓冲区std::string
,以节省异常存储空间。
所以这就是你真正的答案:“非常小心,如果有的话。”
std::runtime_error
您可以通过使用s 作为您自己的异常类的成员来利用 GCC 的慷慨,每个都存储一个字符串。不过,这在 Clang 上仍然没有用。
原始答案,2011 年。这仍然是正确的:
堆栈展开期间的异常导致terminate
调用。
但是构造要抛出的对象不是展开的一部分,并且与throw
表达式之前的代码没有区别。
如果std::runtime_error::runtime_error( std::string const & )
throws std::bad_alloc
,runtime_error
异常将丢失(它从未存在过)并被bad_alloc
处理。
演示:http: //ideone.com/QYPj3
至于您自己的类std::string
从调用站点存储 s,您需要遵循 §18.8.1/2:
从类异常派生的每个标准库类 T 都应具有可公开访问的复制构造函数和可公开访问的复制赋值运算符,它们不会因异常而退出。
这是必需的,因为从堆栈复制到线程的异常存储对异常很敏感。§15.1/7:
如果异常处理机制在完成对要抛出的表达式的求值之后但在捕获异常之前调用通过异常退出的函数,则调用 std::terminate (15.5.1)。
所以,你应该在第一个之后shared_ptr< std::string >
使用一个或一些这样的来清理副本。