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

发布于 2024-12-19 07:03:14 字数 408 浏览 1 评论 0原文

在我的计算机中,try 块中的 new 表达式引发了 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;
    }
}

The new expression in the try block throws a bad_allocexception in my computer.

Note that the catch clause receives an exception object by value, not by reference. How come e.what() prints "bad allocation" ? I thought it would be sliced.

#include <iostream>

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

各自安好 2024-12-26 07:03:14

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

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

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


†此处的内部存储使用松散。它没有内部缓冲区,但有一个 const char* 和一个 bool。 const 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";
    }
};

在这里,切片会影响你的结果。 (也就是说,毕竟:总是通过引用捕获。)

Visual Studio (Dinkumware?) uses an implementation of std::exception that contains internal storage† for the message. (Complete with a non-standard constructor that accepts a string.)

Because of this, no virtual dispatch is actually needed to get the error message, it survives any slicing.

A more orthodox implementation would indeed print a generic exception message, because the derived object was sliced off. (Effectively, MS has made std::exception and std::runtime_error equivalent. There's nothing wrong with this, since the return value of std::exception::what is implementation-defined, but it explains your results.)


†Internal storage here is used loosely. It doesn't have an internal buffer, but it has a const char* and a bool. The const char* points to the message (the return value of what()), and the bool is a flag determining if the buffer should be deleted.

It's like this:

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

You see now that bad_alloc works like this:

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

Slicing doesn't affect the message because the message "exists" in the base class.

Other compilers, like GCC and LLVM, implement it a bit more straight-forwardly:

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

Here, slicing would affect your outcome. (That said, after all this: always catch by reference.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文