How can std::runtime_error::runtime_error(const std::string&) meet std::exception's requirement of throw()?

后端 未结 2 923
栀梦
栀梦 2021-02-07 07:22

std::exception requires that its constructor be throw(). Yet std::runtime_error accepts a std::string as its argument, which

2条回答
  •  悲哀的现实
    2021-02-07 08:01

    Update, 2015:

    Yet std::runtime_error accepts a std::string as its argument, which indicates that it's storing a std::string somewhere. Therefore, an assignment or copy construction has to be going on somewhere. And for std::string, that's not a noexcept operation.

    runtime_error (and logic_error) are only required to accept an argument of type std::string const &. They are not required to copy it.

    Use these overloads at your own peril. LLVM libc++ does not provide storage.

    On the other hand, GNU libstdc++ tiptoes carefully to avoid running out of memory. It copies the contents of the string, but into the exception storage space, not into a new std::string.

    Even then, it adds an std::string&& overload and uses friendship to adopt the internal buffer of a std::string argument passed by rvalue, to conserve exception storage space too.

    So that's your real answer: "Very carefully, if at all."

    You could leverage GCC's generosity by using std::runtime_errors as members of your own exception class, storing one string each. This would still be useless on Clang, though.


    Original answer, 2011. This is still true:

    An exception during stack unwinding causes terminate to be called.

    But constructing the object to be thrown is not part of unwinding, and is treated no differently from the code before the throw expression.

    If std::runtime_error::runtime_error( std::string const & ) throws std::bad_alloc, the runtime_error exception is lost (it never existed) and the bad_alloc is handled instead.

    Demonstration: http://ideone.com/QYPj3

    As for your own class storing std::strings from the call site, you'll want to follow §18.8.1/2:

    Each standard library class T that derives from class exception shall have a publicly accessible copy constructor and a publicly accessible copy assignment operator that do not exit with an exception.

    This is required because copying from the stack to the thread's exception storage is sensitive to exceptions. §15.1/7:

    If the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught, calls a function that exits via an exception, std::terminate is called (15.5.1).

    So, you should use a shared_ptr< std::string > or some such to sanitize copies after the first.

提交回复
热议问题