std::exception. .()在clang和gcc上返回意外值,但在VS11上没有

std::exception.what() returns unexpected value on clang and gcc, but not on VS11

本文关键字:意外 VS11 返回 但在 gcc exception clang std      更新时间:2023-10-16

std::exception. .()及其派生类返回的C字符串的内容是实现定义的,但是clang、gcc和Visual Studio返回的C字符串表示异常类的名称。但是当我在clang 3.2, gcc 4.7和Visual Studio 2012上运行以下代码时,我得到了奇怪的结果:

#include <iostream>
#include <exception>
int main(int argc, const char * argv[])
{
    try {
        throw std::bad_alloc();
    } catch (std::exception e) {
        std::cout << e.what() << std::endl;
    }
    try {
        throw std::bad_alloc();
    } catch (std::bad_alloc e) {
        std::cout << e.what() << std::endl;
    }
    return 0;
}
对于clang和gcc,输出是
std::exception
std::bad_alloc

对于VS11,输出是

bad allocation
bad allocation

我的理解是clang和gcc实现exception::what()类似于

const char* exception::what() const
{
    return __typename_demangle(typeid(*this).name());
}

,并且所有派生类都使用what()方法的实现。如果我在上面的代码中将e.what()替换为typeid(e).name(),那么clang和gcc输出

St9exception
St9bad_alloc

和VS11输出

class std::exception
class std::bad_alloc

我不明白为什么两个catch块的typeid不是std::bad_alloc。这种行为似乎会导致what()方法返回错误的值。微软一定已经为所有从std::exception派生的类创建了不同的、琐碎的what()实现,所以VS11不会受到这个问题的困扰。

您得到这个输出是因为在第一种情况下您创建了一个新的std::exception对象,而在第二种情况下创建了一个新的std::bad_alloc对象。相反,你应该通过引用来捕获异常。下面的代码将显示两者的区别:

#include <iostream>
#include <string>
class Foo
{
public:
    Foo()
    {
        // std::cout << "Foo()" << std::endl;
    }
    Foo(const Foo&)
    {
        std::cout << "Foo(const Foo&)" << std::endl;
    }
    virtual ~Foo()
    {
    }
    virtual std::string what() const
    {
        return "what: Foo";
    }
};
class Bar: public Foo
{
public:
    Bar()
    {
        // std::cout << "Bar()" << std::endl;
    }
    Bar(const Bar&)
    {
        std::cout << "Bar(const Bar&)" << std::endl;
    }
    std::string what() const
    {
        return "what: Bar";
    }
};
int main()
{
    try
    {
        throw Bar();
    }
    catch(Foo f)
    {
        std::cout << f.what() << std::endl;
    }
    try
    {
        throw Bar();
    }
    catch(const Foo& f)
    {
        std::cout << f.what() << std::endl;
    }
    return 0;
}

输出为

Foo(const Foo&)
what: Foo
what: Bar

但是我没有VS11,所以我不能告诉你,为什么VS会产生这样的输出。如果有人能澄清一下就太好了。

感谢@BoPersson:

OP中不同的消息是因为vc++实现了What()通过将消息文本存储在异常基类中。其他