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::terminatei 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_errorma 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_argjest 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 .
nullptrzostał 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.
strcmpjest 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()gdynullptrzostanie przekazane, prawdopodobnie spowoduje problemy.