标准库(STL)容器是否支持一种nothrow分配形式?

Mar*_* Ba 14 c++ stl standard-library

new操作者(或吊舱,的malloc /释放calloc)支持分配的存储器大块,当失败的一个简单而有效的形式.

说我们有这个:

const size_t sz = GetPotentiallyLargeBufferSize(); // 1M - 1000M
T* p = new (nothrow) T[sz];
if(!p) {
  return sorry_not_enough_mem_would_you_like_to_try_again;
}
...
Run Code Online (Sandbox Code Playgroud)

是否有任何这样的std :: containers构造,或者我总是要std::vector和朋友一起处理(预期的!!)异常?


是否有可能有一种方法来编写一个自定义分配器来预分配内存然后将这个自定义分配器传递给向量,这样只要向量不要求比预先放入分配器的内存更多,它就不会失败?


事后的想法:bool std::vector::reserve(std::nothrow) {...}除了正常的储备功能外,还需要一个成员函数.但是,既然只有扩展分配器以允许不进行分配,那只会是有意义的,它就不会发生.似乎(nothrow)新的东西毕竟是好事:-)


编辑:至于为什么我甚至问这个:

调试时我想到了这个问题(调试器的第一次机会/第二次机会异常处理):如果我将我的调试器设置为1st-chance catch任何bad_alloc,因为我正在测试低内存条件,那将是烦人的它还捕获了那些已经很好预期并在代码中处理的bad_alloc异常.这不是/不是一个非常大的问题,但我刚刚发现,布道说异常是针对特殊情况的,而且我已经预期会发生代码中每个奇怪的调用都不例外.

如果new (nothrow)它是合法的用途,那么vector-nothrow-reserve也会有.

tem*_*def 15

默认情况下,标准STL容器类使用std::allocator引擎盖下的类来进行分配,这就是为什么std::bad_alloc如果没有可用内存它们就可以抛出的原因.有趣的是,关于分配器的C++ ISO规范声明任何分配器类型的返回值必须是指向能够容纳一定数量元素的内存块的指针,这会自动阻止您构建可能使用该nothrow版本的自定义分配器.new有这些类型的静默分配失败.但是,如果没有可用的内存,你可以构建一个终止程序的自定义分配器,因为当没有内存时,返回的内存是有效的.:-)

简而言之,标准容器默认情况下抛出异常,并且您可能尝试使用自定义分配器自定义它们以防止抛出异常的任何方式都不符合规范.

  • 调用allocator的大多数方法都没有任何其他方式来报告错误,而不是通过异常. (2认同)

Cas*_*Cow 6

我们经常听到"我不想使用例外,因为它们效率低下".

除非您指的是希望关闭所有运行时类型信息的"嵌入式"环境,否则如果以适当的方式抛出异常,则不应过多担心异常的低效率.内存不足是这些适当的方法之一.

向量合约的一部分是,如果无法分配,它将抛出.如果你编写一个返回NULL的自定义分配器而不是更糟糕,因为它会导致未定义的行为.

如果你必须使用一个分配器,它将首先尝试一个失败分配回调(如果有的话),并且只有当你仍然不能分配到throw时,你仍然必须得到一个例外.

我可以给你一个提示:如果你真的要分配如此大量的数据,那么vector可能是错误的类使用,你应该使用std :: deque.为什么?因为deque不需要连续的内存块,但仍然是恒定的时间查找.优点有两方面:

    • 分配将不那么频繁地失败.因为您不需要连续的块,所以您可能拥有可用的内存,尽管不是在一个块中.
    • 没有重新分配,只有更多的分配.重新分配是昂贵的,因为它需要移动所有对象.当您处于高音量模式时,可以非常及时地进行操作.

当我在过去使用这样一个系统时,我们发现我们实际上可以使用deque存储超过4倍的数据因为我们可以使用向量,因为上面的原因1,并且由于原因2它更快.

我们做的其他事情是分配一个2MB的备用缓冲区,当我们捕获一个bad_alloc时,我们释放了缓冲区,然后扔了以表明我们已达到容量.但是现在有2MB备用,我们至少知道我们有内存来执行小操作来将数据从内存移动到临时磁盘存储.

因此,我们有时可以捕获bad_alloc并采取适当的操作来保持一致状态,这是异常的目的,而不是假设内存耗尽总是致命的,除了终止程序之外永远不应该做任何事情(或者更糟糕的是,调用未定义的行为).