【问题标题】:std::exception.what() returns unexpected value on clang and gcc, but not on VS11std::exception.what() 在 clang 和 gcc 上返回意外值,但在 VS11 上没有
【发布时间】:2013-03-30 07:50:39
【问题描述】:

std::exception.what() 及其派生类返回的 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() 方法返回错误的值。 Microsoft 必须为从 std::exception 派生的所有类创建了不同的、简单的 what() 实现,因此 VS11 不会遇到这个问题。

【问题讨论】:

  • 尝试通过引用捕获异常。
  • 修复了它并回答了问题。通过按值捕获异常,我无意中将 std::bad_alloc 转换为 std::exception 并使其失去了 bad_allocness。有趣的是,VS11 在这两种情况下仍然设法返回“错误分配”。无论如何,如果你回答这个问题,我会接受它。
  • 你看到的现象叫做“对象切片”。

标签: c++ exception-handling typeinfo


【解决方案1】:

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

【讨论】:

  • OP 的不同消息是因为 VC++ 通过将消息文本存储在exception 基类中来实现what()。其他实现则没有。
猜你喜欢
  • 2016-12-20
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
  • 2017-06-08
  • 2017-03-06
  • 2020-01-25
  • 2020-04-15
  • 1970-01-01
相关资源
最近更新 更多