【问题标题】:std::throw_with_nested() on out of memory condition calls std::terminate()std::throw_with_nested() 在内存不足的情况下调用 std::terminate()
【发布时间】:2016-09-14 17:30:08
【问题描述】:

通过随机使malloc() 返回nullptr,我一直在测试一个类,特别是在内存不足情况下发生的情况时,我一直是强有力的异常保证。它使用嵌套异常。

假设我有以下代码:

static std::unordered_map<size_t, size_t> map;
try {
    map.at(0); // Throws std::out_of_range
} catch (...) {
    std::throw_with_nested(std::runtime_error("Input not in map")); // Out of memory here
}

std::throw_with_nested() 最终打电话给std::terminate()

terminate called after throwing an instance of 'std::out_of_range'
  what():  _Map_base::at

Program received signal SIGABRT, Aborted.
0x00007ffff6d96418 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
54  ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007ffff6d96418 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007ffff6d9801a in __GI_abort () at abort.c:89
#2  0x00007ffff76d884d in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007ffff76d66b6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007ffff76d6701 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007ffff76d5472 in __cxa_allocate_exception () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x0000000000425d4c in std::_Throw_with_nested_impl<std::runtime_error, true>::_S_throw<std::runtime_error>(std::runtime_error&&) (
    __t=<unknown type in /path/to/<redacted>, CU 0x2a2a, DIE 0xae780>) at /usr/include/c++/5/bits/nested_exception.h:100
#7  0x000000000041d09f in std::throw_with_nested<std::runtime_error>(std::runtime_error&&) (__t=<unknown type in /path/to/<redacted>, CU 0x2a2a, DIE 0xa3e18>)
    at /usr/include/c++/5/bits/nested_exception.h:137

这是符合标准的预期行为吗?个人感觉应该是直接覆盖旧的异常,或者分配嵌套异常失败就抛出std::bad_alloc

【问题讨论】:

    标签: c++ exception out-of-memory nested-exceptions


    【解决方案1】:

    据我了解,std::nested_exception的构造函数和全局函数std::current_exception()都是noexcept,所以如果其中任何一个发生异常,唯一允许的做法是std::terminate

    【讨论】:

    • 根据 cppreference.com std::current_exception() 只会返回调用本身引起的异常。
    • @josefx 你是对的。这样就留下了外部异常的构造函数。例如,std::runtime_error 包含一个 std::string。如果在投掷过程中投掷,我认为这将被终止。
    • 堆栈跟踪指向 std::throw_with_nested 内部,因此 std::runtime_error 似乎构建没有问题(否则它永远不会调用 std::throw_with_nested)
    猜你喜欢
    • 2014-07-29
    • 2012-06-10
    • 2018-10-20
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    相关资源
    最近更新 更多