为什么需要std :: get_temporary_buffer?


84

我应该出于什么目的使用std::get_temporary_buffer?标准说:

获取一个足以存储最多n个相邻T对象的存储指针。

我以为缓冲区将在堆栈上分配,但这不是事实。根据C ++标准,此缓冲区实际上不是临时的。与全局函数相比,此函数有什么优势,全局函数::operator new也不构造对象。我对以下陈述是否等效?

int* x;
x = std::get_temporary_buffer<int>( 10 ).first;
x = static_cast<int*>( ::operator new( 10*sizeof(int) ) );

该功能仅存在于语法糖吗?为什么有temporary它的名字?


1996年7月1日Dobb博士的日记中提出了一个用例来实现算法:

如果没有缓冲区可以分配,或者小于请求的缓冲区,则该算法仍然可以正常工作,只会减慢速度。


2
仅供参考,std::get_temporary_buffer将在C ++ 17中弃用。
德庆2016年

1
@德清是的 它也将在C ++ 20中被删除,这是有充分理由的(如下所述)。因此,请沿查看器移动
。– Nikos

Answers:


44

Stroustrup在“ The C ++ Programming Language”(第19.4.4节,SE)中说:

这个想法是,系统可以保留许多固定大小的缓冲区以备快速分配,以便对n个对象的请求空间可以产生大于n的空间。但是,它的收益也可能更少,因此一种使用方式get_temporary_buffer()是乐观地要求很多,然后使用碰巧可用的方式。
[...]由于get_temporary_buffer()级别较低,并且可能已针对管理临时缓冲区进行了优化,因此不应将它用作newallocator :: allocate()的替代方法以获得长期存储。

他还通过以下内容开始介绍这两个功能:

算法通常需要临时空间才能令人满意地执行。

...但是似乎在任何地方都没有提供临时长期的定义。

一个故事中的“从数学到泛型编程”提到,斯捷潘诺夫在原来的STL的设计但前提是伪造的占位符的实现,:

令他惊讶的是,几年后,他发现提供STL实现的所有主要供应商仍在使用这种可怕的实现[...]


12
看起来VC ++的实现只是一个循环,operator new使用依次较小的参数进行调用,直到分配成功为止。那里没有特殊的优化。
jalf

9
与g ++ 4.5相同-似乎是出于本意,但被供应商忽略。
乔治·弗里茨彻

4
听起来他们应该将此功能包装在称为crazy_allocator
0xbadf00d

但是,让我们保持认真-也许会很乐意分配很多存储空间。我们现在所能做的就是要求系统使用大量存储资源get_temporary_buffer。但是,如果我们收到的金额少于要求的数量(这是真正的遗憾),我们将继续尝试使用已有的存储进行工作。可能比捕获bad_alloc由尝试分配超出可用内存的内存所导致的异常更好。但是,真正的实用性不失为一个好的实现。
0xbadf00d

@jalf在C ++ 17中已不推荐使用:)(根据cppreference.com)。
4LegsDrivenCat

17

微软的标准库专家说(在这里):

  • 您能否解释一下何时使用“ get_temporary_buffer”

它有一个非常专门的目的。请注意,它不会像new(nothrow)一样抛出异常,但它也不会构造对象,与new(nothrow)不同。

它由STL在内部使用在诸如stable_partition()之类的算法中。当存在像N3126 25.3.13 [alg.partitions] / 11这样的魔术词时,就会发生这种情况:stable_partition()的复杂度“最多(最后-优先)* log(最后-优先)交换,但只有线性交换数(如果存在)足够的额外内存。” 当出现“如果有足够的额外内存”这句话时,STL使用get_temporary_buffer()尝试获取工作空间。如果可以,则可以更有效地实现该算法。否则,由于系统危险地接近内存不足(或涉及的范围很大),因此该算法可能会退回到较慢的技术上。

99.9%的STL用户将永远不需要了解get_temporary_buffer()。


9

该标准说,它最多可以分配存储 n元素。换句话说,您的示例可能返回的缓冲区仅足以容纳5个对象。

但是,很难想象有一个很好的用例。也许如果您正在一个非常受内存限制的平台上工作,那么这是获取“尽可能多的内存”的便捷方法。

但是在这样一个受限制的平台上,我想您会尽可能地绕过内存分配器,而使用内存池或您完全控制的东西。


4

我应该出于什么目的使用 std::get_temporary_buffer?

该函数在C ++ 17中已弃用,因此正确的答案现在是“无目的,不要使用它”。


2
ptrdiff_t            request = 12
pair<int*,ptrdiff_t> p       = get_temporary_buffer<int>(request);
int*                 base    = p.first;
ptrdiff_t            respond = p.sencond;
assert( is_valid( base, base + respond ) );

回应可能少于要求

size_t require = 12;
int*   base    = static_cast<int*>( ::operator new( require*sizeof(int) ) );
assert( is_valid( base, base + require ) );

基数的实际大小必须大于或等于要求


2

也许(只是一个猜测)与内存碎片有关。如果您大量地分配和取消分配临时内存,但是每次执行此操作时,您都会在分配临时内存之后但在取消分配临时内存之前分配一些长期的预期内存,您最终可能会遇到碎片化的堆(我想)。

因此,get_temporary_buffer可能打算成为比您需要的内存块更大的内存块,该内存块将被分配一次(也许有很多块准备好接受多个请求),并且每次需要内存时,您只会得到其中一个大块。因此,内存不会碎片化。


1
非常有趣的想法。尽管它目前似乎已被大多数实现实现为可以工作的事情,但它很可能会得到更紧密的支持,并与其余的内存管理例程集成在一起。我投票给我们,实际上是希望它适合它,而Bjarnes的评论似乎也暗示了这一点。
gustaf r

我现在一直在寻找Bjarne所说的话,他说它是为无需初始化的快速分配而设计的。因此,这就像一个仅分配程序的(非初始化程序)void *运算符new(size_t size),但是分配起来更快,因为它是预先分配的。
Daniel Munoz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.