¿Cómo construir una excepción <stdexcept> o <system_error> sin lanzar?

Excepciones definidas en<stdexcept> (p.ej.std::logic_error, std::runtime_error y sus subclases comostd::system_error) tienen constructores que esperan argumentos de cadena, por ejemplo:

domain_error(const string& what_arg);
domain_error(const char* what_arg);

con postcondiciones

strcmp(what(), what_arg.c_str()) == 0
strcmp(what(), what_arg) == 0

respectivamente. No hay ningún requisito de que estos argumentos pasados a los constructores sigan siendo válidos durante la vigencia de estas excepciones, por lo que la única forma de garantizar que se cumplan las condiciones posteriores esduplicar y almacenar estas cadenas dinámicas. Esto requiere memoria, por lo que supongo que su construcción en sí misma puede arrojarstd::bad_alloc o similar, que suele sermás inesperado. Esto causa problemas, porque cada ejemplo de código que he visto en la naturaleza alienta a las personas a escribir código como

if (haveError)
    throw std::runtime_error("BOO!"); // May throw std::bad_alloc instead?!

mientras que sería mucho más seguro construir la excepción de antemano en otro lugar, por ejemplo:

struct A {
    // During allocation of A one would often expect std::bad_alloc anyway:
    A() : m_someException("BOO!") {}
    void f() {
        /* Do stuff */
        if (haveError)
            throw m_someException;
            /* Note that according to §18.8.1.2 all standard library
               classes deriving from `std::exception` must have publicly
               accessible copy constructors and copy assignment operators
               that do not exit with an exception. In implementations such
               exception instances most likely share the common string
               with all their copies. */
    }
    std::runtime_error const m_someException;
};

Esto me hace muy cauteloso con las bibliotecas que lanzan tales excepciones, por ejemplo, inclusoregex_error de<regex> en C ++ 11 !!!

¿Por qué estas excepciones no tienen constructores no-throw / noexcept? ¿Las directrices básicas de C ++ tienen algo que decir sobre esto?

PD: personalmente me hubiera idowhat() un método abstracto puro en este punto en la cadena de ascendencia de excepción.

EDITAR 09.10.2017: Aquí hay un PoC que demuestra questd::runtime_error la construcción puede arrojar unstd::bad_alloc en lugar:

#include <cstddef>
#include <cstdlib>
#include <new>
#include <stdexcept>
#include <string>

bool throwOnAllocate = false;

void * operator new(std::size_t size) {
    if (!throwOnAllocate)
        if (void * const r = std::malloc(size))
            return r;
    throw std::bad_alloc();
}

void operator delete(void * ptr) { std::free(ptr); }

int main() {
    std::string const errorMessage("OH NOEZ! =(");
    throwOnAllocate = true;
    throw std::runtime_error(errorMessage);
}

Respuestas a la pregunta(4)

Su respuesta a la pregunta