为什么`e.what()`打印“错误分配”?

时间:2011-11-30 23:30:15

标签: c++ visual-studio-2008 exception-handling object-slicing

new块中的try表达式会在我的计算机中引发bad_alloc异常。

请注意,catch子句按值接收异常对象,而不是通过引用。 e.what()如何打印"bad allocation"?我以为它会被切成碎片。

#include <iostream>

int main()
{
    try
    {
        int* p = new int[0x1F000000];
    }
    catch(std::exception e)
    {
        std::cout << e.what() << std::endl;
    }
}

1 个答案:

答案 0 :(得分:13)

Visual Studio(Dinkumware?)使用std::exception的实现,其中包含消息的内部存储†。 (使用接受字符串的非标准构造函数完成。)

因此,实际上不需要虚拟调度来获取错误消息,它可以在任何切片中存活。

更正统的实现确实会打印一个通用的异常消息,因为派生的对象被切掉了。 (实际上,MS已经使std::exceptionstd::runtime_error等效。这没有任何问题,因为std::exception::what的返回值是实现定义的,但它解释了你的结果。)


†这里的内部存储空间很宽松。它没有内部缓冲区,但它有const char*boolconst char*指向消息(what()的返回值),bool是一个标志,用于确定是否应删除缓冲区。

就是这样:

class msvc_exception // for exposition
{
public:
    msvc_exception(const char* msg) :
    mMsg(msg),
    mDoDelete(false)
    {}

    msvc_exception(const std::string& msg) :
    mMsg(copy_string(msg)),
    mDoDelete(true)
    {}

    virtual ~msvc_exception()
    {
        if (mDoDelete)
            delete [] mMsg;
    }

    virtual const char* what() const throw()
    {
        return mMsg ? mMsg : "unknown";
    }

private:
    const char* copy_string(const std::string& str)
    {
        const char* result = new char[str.size() + 1];

        std::copy(str.begin(), str.end(), result);
        result[str.size()] = 0; // null-terminate

        return result;
    }
};

您现在看到bad_alloc的工作原理如下:

    class msvc_bad_alloc : // for exposition
        public msvc_exception
    {
    public:
        msvc_bad_alloc() :
        msvc_exception("bad_alloc") // note: a static string, no dynamic storage
        {}
    };

切片不会影响邮件,因为基类中的邮件“存在”。

其他编译器,如GCC和LLVM,更直接地实现它:

class orthodox_exception
{
public:
    orthodox_exception(){}
    virtual ~orthodox_exception() {}

    virtual const char* what() const throw()
    {
        return "orthodox_exception";
    }
};

class orthodox_bad_alloc :
    public orthodox_exception
{
public:
    const char* what() const throw()
    {
        return "orthodox_bad_alloc";
    }
};

在这里,切片会影响你的结果。 (也就是说,毕竟这一点:总是引用参考。)