2013-03-30 42 views
2

std :: exception.what()及其派生类返回的C字符串的内容是实现定义的,但clang, gcc和Visual Studio会返回指示异常类名称的C字符串。但是,当我在铿锵3.2,GCC 4.7,和的Visual Studio 2012运行下面的代码,我得到了奇怪的结果:std :: exception.what()在clang和gcc上返回意外值,但不在VS11上

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

铿锵和GCC的输出

std::exception 
std::bad_alloc 

随着VS11输出

bad allocation 
bad allocation 

我的理解是,铛和gcc执行异常:什么()像这样

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

并且所有派生类都使用what()方法的这个实现。如果我更换e.what()typeid的(E)。名称()在上面的代码然后铛和gcc输出

St9exception 
St9bad_alloc 

和VS11输出

class std::exception 
class std::bad_alloc 

我不不要理解为什么typeid不是std :: bad_alloc的两个catch块。此行为似乎导致what()方法返回错误的值。微软必须为std :: exception的所有类创建what()的不同的简单实现,所以VS11不会遇到这个问题。

+3

尝试通过引用来捕获异常。 – soon

+0

修复它并回答问题。通过捕获异常的价值,我不知不觉地将std :: bad_alloc转换为std :: exception,并使其失去bad_allocness。有趣的是,VS11在这两种情况下仍然设法返回“不良分配”。无论如何,如果你回答这个问题,我会接受它。 – MtnViewJohn

+3

你看到的现象被称为“物体切片”。 –

回答

3

你得到这个输出是因为在第一种情况下你创建一个新的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++通过存储在异常基类中的消息文本实现 什么()。其他 实现不。

+3

OP中的不同消息是因为VC++通过将消息文本存储在'exception'基类中来实现'what()'。其他实现不。 –