Considere el siguiente programa:
#include<stdexcept>
#include<iostream>
int main() {
try {
throw std::range_error(nullptr);
} catch(const std::range_error&) {
std::cout << "Caught!\n";
}
}
GCC y Clang con libstdc ++ llaman std::terminate
y cancelan el programa con el mensaje
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Clang con libc ++ segfaults en la construcción de la excepción.
Ver Godbolt .
¿Los compiladores se comportan conforme a la norma? La sección relevante del estándar [diagnostics.range.error] (C ++ 17 N4659) dice que std::range_error
tiene una const char*
sobrecarga del constructor que debería preferirse a la const std::string&
sobrecarga. La sección tampoco establece condiciones previas en el constructor y solo establece la condición posterior
Condiciones posteriores :
strcmp(what(), what_arg) == 0
.
Esta condición posterior siempre tiene un comportamiento indefinido si what_arg
es un puntero nulo, entonces, ¿significa esto que mi programa también tiene un comportamiento indefinido y que ambos compiladores actúan conforme? Si no es así, ¿cómo debería uno leer tales postcondiciones imposibles en el estándar?
Pensándolo bien, creo que debe significar un comportamiento indefinido para mi programa, porque si no fuera así, los punteros (válidos) que no apuntan a cadenas terminadas en nulo también estarían permitidos, lo que claramente no tiene sentido.
Entonces, suponiendo que eso sea cierto, me gustaría centrar la pregunta más en cómo el estándar implica este comportamiento indefinido. ¿Se deduce de la imposibilidad de la condición posterior que la llamada también tiene un comportamiento indefinido o simplemente se olvidó la condición previa?
Inspirado por esta pregunta .
nullptr
se aprueba, creo que what()
tendría que desreferenciarlo en algún momento para obtener el valor. Eso sería desreferenciar a nullptr
, lo cual es problemático en el mejor de los casos y es seguro que colapsar sea peor.
strcmp
se usa para describir el valor de what_arg
. Eso es lo que dice la sección relevante del estándar C de todos modos, a lo que se refiere la especificación de <cstring>
. Por supuesto, la redacción podría ser más clara.
what()
cuandonullptr
se pasa probablemente causaría problemas.