Рассмотрим следующую программу:
#include<stdexcept>
#include<iostream>
int main() {
try {
throw std::range_error(nullptr);
} catch(const std::range_error&) {
std::cout << "Caught!\n";
}
}
GCC и 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 при построении исключения.
Вижу Годболт .
Ведут ли компиляторы стандартное соответствие? В соответствующем разделе стандарта [ Diagnics.range.error ] (C ++ 17 N4659) сказано, что std::range_errorимеется const char*перегрузка конструктора, которая должна быть предпочтительнее const std::string&перегрузки. В разделе также не указываются никакие предварительные условия для конструктора, а только указывается постусловие.
Постусловия :
strcmp(what(), what_arg) == 0.
Это постусловие всегда имеет неопределенное поведение, если what_argявляется нулевым указателем, значит ли это, что моя программа также имеет неопределенное поведение и что оба компилятора действуют согласованно? Если нет, то как следует читать такие невозможные постусловия в стандарте?
Во-вторых, я думаю, что это должно означать неопределенное поведение для моей программы, потому что, если это не так, то (допустимые) указатели, не указывающие на строки с нулевым символом в конце, также будут разрешены, что явно не имеет смысла.
Итак, предполагая, что это правда, я хотел бы сосредоточить вопрос больше на том, как стандарт подразумевает это неопределенное поведение. Из невозможности постусловия следует, что вызов также имеет неопределенное поведение, или предусловие было просто забыто?
Вдохновлен этим вопросом .
nullptrбудет принято, я думаю, что what()в какой-то момент придется разыменовать его, чтобы получить значение. Это было бы разыменованием a nullptr, которое в лучшем случае проблематично, а наверняка к краху - хуже всего.
strcmpиспользуется для описания значения what_arg. Это то, что в любом случае говорится в соответствующем разделе стандарта C , на который ссылается спецификация <cstring>. Конечно, формулировка может быть более понятной.
what()когдаnullptrпрошло, вероятно, вызовет проблемы.