[Spice-devel] [PATCH 12/22] Add exception handling classes

Christophe de Dinechin cdupontd at redhat.com
Wed Mar 28 15:42:22 UTC 2018


Somewhat OT, but hopefully informative in the context of this thread.


> On 26 Mar 2018, at 18:24, Jonathon Jongsma <jjongsma at redhat.com> wrote:
> 
> As teuf mentioned in a different email, std::runtime_error in C++11 has a const char* constructor:

Since the presence of this constructor was used repeatedly as an argument, I’ve asked a few times if someone could tell me why this constructor was added in C++ 11. So far, nobody answered. I did not think it was so hard to google it. Oh well, since nobody else took up the challenge, time for me to answer the question…

Here is one source giving a relatively short explanation: https://stackoverflow.com/questions/29052647/c11-introduced-exception-constructors-taking-const-char-but-why. I quote: "This allows (or at least is apparently intended to facilitate--see more below) the implementation to eliminate copies in cases where it can detect (by means that are not themselves standardized) that what's being passed is a string literal or something else with static storage duration.” See also the note at the end of that answer: "[ Oxford: The proposed resolution simply addresses the issue of constructing the exception objects with const char* and string literals without the need to explicit include or construct a std::string. ]”

So what happened is that the committee knew that having an std::string constructed for all runtime errors was problematic, as far back as 2000. This is defect 254, see http://std.dkuug.dk/jtc1/sc22/wg21/docs/lwg-closed.html. It was a bit annoying if implementors took a great deal of care and effort to ensure that you could throw an exception reliably in low-memory situations (see section 4.2.2 of https://github.com/itanium-cxx-abi/cxx-abi/blob/master/HP-exception-990818.pdf if you are curious about the kind of shenanigans I’m talking about) only to see all these effort thwarted by the (legacy) interface of std::runtime_error.

However, you can imagine that back in 2000, deciding to remove the std::string constructor was difficult. So the problem was not easy to fix, and it shouldn’t be too hard to believe that there was a lot of discussion (254 is listed as one of the hot topics for the Redmond meeting). Before the Oxford meeting, the decision was to accept throwing bad_alloc as a fact of life. But as you can see at the bottom of bug 254, the consensus on a better longer-term resolution for C++0x, which became C++11, was to add a const char * that would allow the implementation to special-case std::runtime_error and avoid the copy. In the Oxford meeting, that resolution was confirmed, and the change made it to C++11.

Out of curiosity, I checked both clang and g++, and they don’t actually store a string in std::runtime_error, I suspect in large part because of another related issue, namely the risk of throwing from string copy constructors. though they don’t seem to be doing the optimization either, because it’s quite hard relative to the benefits :-( So no worries, on clang, if you are really out of memory, you will not throw bad_allloc or end up in terminate(). No sir, the standard forbids it. No, instead, you will segfault writing into a null pointer (line 74 of https://llvm.org/viewvc/llvm-project/libcxx/trunk/src/include/refstring.h?view=markup if you are curious). So much better.

Bottom line: the very reason there is a const char * constructor in std::runtime_error is to provide a workaround for a known design bug. There is no value in blindly repeating that design bug.


Cheers,
Christophe



More information about the Spice-devel mailing list