Rozważ następujący program:
#include<stdexcept>
#include<iostream>
int main() {
try {
throw std::range_error(nullptr);
} catch(const std::range_error&) {
std::cout << "Caught!\n";
}
}
GCC i Clang z wywołaniem libstdc ++ std::terminate
i przerywają program z komunikatem
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Clang z libc ++ segfaults przy budowie wyjątku.
Zobacz godbolt .
Czy kompilatory zachowują się zgodnie ze standardami? Odpowiednia sekcja standardu [diagnostics.range.error] (C ++ 17 N4659) mówi, że std::range_error
ma const char*
przeciążenie konstruktora, które powinno być lepsze niż const std::string&
przeciążenie. Sekcja nie zawiera również żadnych warunków wstępnych dotyczących konstruktora i podaje jedynie warunek końcowy
Postconditions :
strcmp(what(), what_arg) == 0
.
Ten warunek zawsze ma niezdefiniowane zachowanie, jeśli what_arg
jest wskaźnikiem zerowym, więc czy to oznacza, że mój program ma również niezdefiniowane zachowanie i że oba kompilatory działają zgodnie? Jeśli nie, to jak należy odczytać takie niemożliwe warunki w normie?
Po zastanowieniu, myślę, że musi to oznaczać niezdefiniowane zachowanie mojego programu, ponieważ jeśli nie, to (prawidłowe) wskaźniki dozwolone w łańcuchach zakończonych znakiem zerowym również byłyby dozwolone, co oczywiście nie ma sensu.
Zakładając, że to prawda, chciałbym bardziej skoncentrować pytanie na tym, jak standard implikuje to niezdefiniowane zachowanie. Czy z niemożności spełnienia warunku wynika, że wezwanie ma również niezdefiniowane zachowanie, czy też warunek ten został po prostu zapomniany?
Zainspirowany tym pytaniem .
nullptr
został zaliczony, pomyślałbym, what()
że w pewnym momencie musiałbym go odrzucić, aby uzyskać wartość. To byłoby dereferencjonowanie a nullptr
, co w najlepszym wypadku jest problematyczne i na pewno jest najgorsze.
strcmp
jest on używany do opisania wartości what_arg
. Tak zresztą mówi odpowiednia sekcja normy C , do której odwołuje się specyfikacja <cstring>
. Oczywiście sformułowanie może być jaśniejsze.
what()
gdynullptr
zostanie przekazane, prawdopodobnie spowoduje problemy.