[英]Slicing std::out_of_range to std::exception in Visual Studio vs g++
我偶然注意到了以下行为(错过了通过引用捕捉),但我找不到信息,如果我事先知道的话,可以让我预测它。
用最小的例子
#include <iostream>
#include <stdexcept>
int main()
{
try
{
// Added this and the next line to check that the exception
// created has already the what() set to the input string.
std::out_of_range d("Out of range exception");
std::cout << "d.what() = " << d.what() << std::endl;
throw d;
}
catch (std::exception e) // Captured by value
{
std::cout << e.what() << std::endl;
}
}
如果我用g++ -std=c++17
和 Visual C++ 编译它,我会得到不同的行为。 第一个它打印d.what() = Out of range exception\\nstd::exception
,而第二个它打印d.what() = Out of range exception\\nOut of range exception
。
原则上,当std::out_of_range
被值捕获并转换为std::exception
类型时,可能会进行切片。 这意味着在打印其what()
时,我可能不会获得与来自std::out_of_range
对象的对象相同的行为。
问题:我不知道如何解释的部分是两个编译器的行为不同。 这是因为这种切片在 C++ 标准化中是未定义的行为,还是这两个编译器之一不符合它?
额外的观察:我只是注意到在此链接中没有提到类std::exception
具有输入const char* const &
的构造const char* const &
,而在Microsoft 网站中它们包含它。 我偶然的例子表明他们确实以不同的方式实现了这些类。 我的问题仍然是他们是否被允许(如果此行为未定义)或者其中一个不遵守以及哪一个不遵守。
对象仍在切片中; 您可以使用typeid( e ).name()
打印出实际类型,它显示为std::exception
。 如您所见,MSVC 实现what()
以返回指向在std::exception
构造时设置的字符串的指针,因此当out_of_range
异常被切回基本异常时它不会丢失。
根据https://en.cppreference.com/w/cpp/error/exception/exception , what() “返回一个实现定义的字符串”,所以 MSVC 可以自由地这样做。
要打印类型,请将其添加到您的 catch 块中:
std::cout << "e.what() = " << e.what() << " 实际类型 = " << typeid( e).name() << std::endl;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.