简体   繁体   English

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

[英]Slicing std::out_of_range to std::exception in Visual Studio vs g++

I noticed the following behavior by accident (missed catching by reference), but I couldn't find information that, if I knew it before hand, would have allowed me to predict it.我偶然注意到了以下行为(错过了通过引用捕捉),但我找不到信息,如果我事先知道的话,可以让我预测它。

With the minimal example用最小的例子

#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;
    }

}

If I compile it with g++ -std=c++17 and with Visual C++ I get different behaviors.如果我用g++ -std=c++17和 Visual C++ 编译它,我会得到不同的行为。 With the first it prints d.what() = Out of range exception\\nstd::exception , while the second it prints d.what() = Out of range exception\\nOut of range exception .第一个它打印d.what() = Out of range exception\\nstd::exception ,而第二个它打印d.what() = Out of range exception\\nOut of range exception

In principle there could be slicing when the std::out_of_range is captured by value and converted to the std::exception type.原则上,当std::out_of_range被值捕获并转换为std::exception类型时,可能会进行切片。 This means that I could expect not getting the same behavior as an object from std::out_of_range object when printing its what() .这意味着在打印其what()时,我可能不会获得与来自std::out_of_range对象的对象相同的行为。

Question: The part that I don't know how to explain is getting different behaviors for the two compilers.问题:我不知道如何解释的部分是两个编译器的行为不同。 Is this because this slicing is undefined behavior in the C++ standarization, or is it that one of these two compilers is not complying with it?这是因为这种切片在 C++ 标准化中是未定义的行为,还是这两个编译器之一不符合它?

Extra observation: I just noticed that in this link there is no mention of the class std::exception having a constructor that inputs a const char* const & , while in the Microsoft website they include it.额外的观察:我只是注意到在此链接中没有提到类std::exception具有输入const char* const &的构造const char* const & ,而在Microsoft 网站中它们包含它。 My accidental example shows that they indeed implemented these classes differently.我偶然的例子表明他们确实以不同的方式实现了这些类。 My question is still whether they were allowed (if this behavior is undefined) or if one of them is not complying and which one.我的问题仍然是他们是否被允许(如果此行为未定义)或者其中一个不遵守以及哪一个不遵守。

The object is still being sliced;对象仍在切片中; you can use typeid( e ).name() to print out the actual type and it shows as std::exception .您可以使用typeid( e ).name()打印出实际类型,它显示为std::exception As you found, MSVC implements what() to return a pointer to a string that is set at std::exception construction time, so it's not lost when the out_of_range exception is sliced back into the base exception.如您所见,MSVC 实现what()以返回指向在std::exception构造时设置的字符串的指针,因此当out_of_range异常被切回基本异常时它不会丢失。

Per https://en.cppreference.com/w/cpp/error/exception/exception , what() "returns an implementation-defined string" so MSVC is free to do it this way.根据https://en.cppreference.com/w/cpp/error/exception/exception , what() “返回一个实现定义的字符串”,所以 MSVC 可以自由地这样做。

To print the type, add this to your catch block:要打印类型,请将其添加到您的 catch 块中:

std::cout << "e.what() = " << e.what() << " Actual type = " << typeid( e ).name() << std::endl; 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