繁体   English   中英

在 Visual Studio 与 g++ 中将 std::out_of_range 切片为 std::exception

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM