【问题标题】:memory allocation failure during map/unordered_map insertionmap/unordered_map 插入期间的内存分配失败
【发布时间】:2020-07-29 13:33:06
【问题描述】:

我无法捕捉到在插入地图时分配内存失败,这导致由于分段错误而导致崩溃。

struct Data
{
    int64_t arr[100000000000000000]; // Large data to cause allocation failure
};

typedef unordered_map<int64_t, Data> UOM;

int main()
{
    //void* p = malloc(sizeof(int64_t)*100000000000000000);
    //void* p = new int64_t [100000000000000000];
    //cout <<p <<endl;
    
    UOM m;
    try
    {
        m[1];
    } catch(...)
    {
    }
}

如果我们使用 malloc 它将返回一个 NULL 而 new 抛出 std::bad_alloc 可以被捕获。但是,需要分配此内存的插入 map 会崩溃(出现分段错误)。

为什么会这样?按照标准应该是什么行为?

编辑:平台、编译器是:Redhat 6.10 上带有“-std=c++11”标志的旧编译器 g++ 4.7.1。是的,我们生活在石器时代!

【问题讨论】:

  • 为什么会这样?
  • 不能捕获内存分配错误。请注意,如果我们直接 new/malloc 可以捕获相同的分配失败。
  • 我可以在我的机器上捕捉到std::bad_alloc(正在抛出)。
  • 为我工作godbolt.org/z/q1dbrq
  • 我认为你只看到了一条日志消息,但异常被正确捕获

标签: c++ exception out-of-memory new-operator


【解决方案1】:

您正在尝试在 try ... catch 块之外创建 m 对象(并因此导致 bad_alloc 错误)。将try 'back' 移动一级,您将捕获异常:

int main()
{
    try {
        UOM m;
        m[1];
    }
    catch (...) {
        std::cout << "Caught!" << std::endl;
    }
    return 0;
}

编辑:另请注意,以下内容会捕获异常在创建时(使用 clang-cl,完全优化):

int main()
{
    UOM* m;
    try {
        m = new UOM;
    }
    catch (...) {
        std::cout << "Caught at creation!" << std::endl;
        return 0;
    }
    try {
        (*m)[1];
    }
    catch (...) {
        std::cout << "Caught at insertion!" << std::endl;
    }
    delete m;
    return 0;
}

编辑#2:这可能是std::unordered_map 的默认构造函数的实现定义行为,如cppreference 所示:

(1) 构造空容器。将 max_load_factor() 设置为 1.0。为了 默认构造函数,桶数由实现定义。

【讨论】:

  • 我不认为这会改变任何东西,错误发生在m[1];,如果你在一行中使用UOM m; 运行此代码,没有任何改变
  • @Berto99 可能是编译器优化 - 将声明与插入合并。
  • 那将是一个无效的“优化”,因为它改变了程序的可观察结果
  • @Caleth 我同意 - 我只是在“大声思考”。见编辑。
  • 我不确定为什么存储桶需要实际分配数据,以及为什么转义异常会出现段错误(如果这是正常行为,请纠正我)。如果您可以在在线编译器中重现它,那就太好了。我在 Wandbox 上尝试了 gcc9 和 clang10,但它只在插入时抛出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-01
  • 2013-02-19
  • 2011-12-12
  • 2011-08-23
  • 1970-01-01
  • 2018-03-23
相关资源
最近更新 更多