Рассмотрим следующую программу:
#include<stdexcept>
#include<iostream>
int main() {
try {
throw std::range_error(nullptr);
} catch(const std::range_error&) {
std::cout << "Caught!\n";
}
}
G CC и Clang с вызовом libstdc ++ std::terminate
и прерывание программы с сообщением
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Clang с libc ++ segfaults on Конструкция исключения.
См. godbolt .
Ведут ли компиляторы стандартное соответствие? В соответствующем разделе стандарта [одиагностика.ренажа] (C ++ 17 N4659) действительно говорится, что std::range_error
имеет перегрузку конструктора const char*
, которая должна быть предпочтительнее перегрузки const std::string&
. В разделе также не указываются никакие предварительные условия для конструктора, а указывается только постусловие
Постусловия : strcmp(what(), what_arg) == 0
.
Это постусловие всегда имеет неопределенное поведение, если what_arg
является нулевым указателем, значит ли это, что моя программа также имеет неопределенное поведение и что оба компилятора действуют согласованно? Если нет, то как следует читать такие невозможные постусловия в стандарте?
Если подумать, я думаю, что это должно означать неопределенное поведение для моей программы, потому что если это не так (действительные) указатели не Также разрешается указывать на строки с нулевым символом в конце, что явно не имеет смысла.
Итак, предполагая, что это правда, я бы хотел больше сосредоточиться на вопросе о том, как стандарт подразумевает это неопределенное поведение. Из невозможности постусловия следует, что вызов также имеет неопределенное поведение или просто забыли предусловие?
Вдохновленный этим вопросом .