考虑以下程序:
#include<stdexcept>
#include<iostream>
int main() {
try {
throw std::range_error(nullptr);
} catch(const std::range_error&) {
std::cout << "Caught!\n";
}
}
使用libstdc ++调用的GCC和Clang std::terminate
并通过消息中止程序
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
用libc ++ segfaults构造异常的Clang。
见godbolt。
编译器的行为符合标准吗?标准[diagnostics.range.error](C ++ 17 N4659)的相关部分确实说std::range_error
有const char*
构造函数重载,应该优先于const std::string&
重载。本节也没有说明构造函数的任何前提条件,而只说明了后置条件
后置条件:
strcmp(what(), what_arg) == 0
。
如果what_arg
为空指针,则此后置条件始终具有未定义的行为,那么这是否意味着我的程序也具有未定义的行为并且两个编译器的行为一致?如果没有,应该如何阅读标准中如此不可能的后置条件?
再次考虑,我认为这一定意味着程序的未定义行为,因为如果不这样做,那么(有效)不指向以null终止的字符串的指针也将被允许,这显然没有意义。
因此,假设这是真的,我想将问题更多地集中在标准如何暗示这种未定义的行为上。是由于后置条件的不可能而导致调用也具有未定义的行为,还是先决条件被简单地忘记了?
受到这个问题的启发。
nullptr
通过了,我认为what()
必须在某个时候取消引用它以获得值。那将取消引用nullptr
,这充其量是有问题的,并且肯定会崩溃是最坏的情况。
what()
何时调用nullptr
可能会导致问题。