Betrachten Sie das folgende Programm:
#include<stdexcept>
#include<iostream>
int main() {
try {
throw std::range_error(nullptr);
} catch(const std::range_error&) {
std::cout << "Caught!\n";
}
}
GCC und Clang mit libstdc ++ rufen std::terminate
das Programm mit der Nachricht auf und brechen es ab
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Klirren Sie mit libc ++ segfaults beim Aufbau der Ausnahme.
Siehe Godbolt .
Verhalten sich die Compiler standardkonform? Der relevante Abschnitt des Standards [diagnostics.range.error] (C ++ 17 N4659) besagt, dass std::range_error
eine const char*
Konstruktorüberladung vorliegt, die der const std::string&
Überladung vorzuziehen ist . Der Abschnitt enthält auch keine Voraussetzungen für den Konstruktor und nur die Nachbedingung
Nachbedingungen :
strcmp(what(), what_arg) == 0
.
Diese Nachbedingung hat immer ein undefiniertes Verhalten, wenn what_arg
es sich um einen Nullzeiger handelt. Bedeutet dies also, dass mein Programm auch ein undefiniertes Verhalten aufweist und beide Compiler konform handeln? Wenn nicht, wie sollte man solche unmöglichen Nachbedingungen im Standard lesen?
Beim zweiten Gedanken denke ich, dass dies undefiniertes Verhalten für mein Programm bedeuten muss, denn wenn dies nicht der Fall wäre, wären auch (gültige) Zeiger zulässig, die nicht auf nullterminierte Zeichenfolgen zeigen, was eindeutig keinen Sinn ergibt.
Unter der Annahme, dass dies zutrifft, möchte ich die Frage mehr darauf konzentrieren, wie der Standard dieses undefinierte Verhalten impliziert. Folgt aus der Unmöglichkeit der Nachbedingung, dass der Anruf auch ein undefiniertes Verhalten aufweist oder wurde die Vorbedingung einfach vergessen?
Inspiriert von dieser Frage .
nullptr
bestanden wird, würde ich denken, dass es what()
irgendwann dereferenzieren müsste, um den Wert zu erhalten. Das wäre eine Dereferenzierung von a nullptr
, die bestenfalls problematisch ist und mit Sicherheit am schlimmsten ist.
strcmp
es zur Beschreibung des Werts von verwendet wird what_arg
. Das sagt sowieso der relevante Abschnitt aus der C-Norm , auf den sich die Spezifikation von bezieht <cstring>
. Natürlich könnte der Wortlaut klarer sein.
what()
wenn ernullptr
bestanden wird, würde wahrscheinlich Probleme verursachen.