次のプログラムを検討してください。
#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 ++のClangがsegfaultします。
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
おそらく問題が発生します。