87

我应该使用什么目的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 博士期刊中提出了一个用于实现算法的用例:

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

4

6 回答 6

47

Stroustrup 在“C++ 编程语言”第 19.4.4 节,SE)中说:

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

他还开始介绍这两个函数:

算法通常需要临时空间才能以可接受的方式执行。

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

“从数学到通用编程”中的一则轶事提到 Stepanov 在原始 STL 设计中提供了一个虚假的占位符实现,但是:

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

于 2010-07-16T12:06:16.963 回答
19

微软标准库的人说以下(这里):

  • 您能否解释一下何时使用“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()。

于 2014-11-11T09:07:37.490 回答
9

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

不过,似乎很难想象一个好的用例。也许如果您在一个内存非常有限的平台上工作,那么这是一种获得“尽可能多的内存”的便捷方式。

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

于 2010-07-16T11:37:28.087 回答
6

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

The function is deprecated in C++17, so the correct answer is now "for no purpose, do not use it".

于 2017-12-06T23:11:10.987 回答
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 ) );

base的实际大小必须大于或等于require

于 2010-07-16T11:41:08.063 回答
2

也许(只是猜测)它与内存碎片有关。如果您不断地分配和释放临时内存,但每次执行此操作时,您都会在分配临时内存之后但在释放临时内存之前分配一些长期预期内存,您最终可能会得到一个碎片堆(我猜)。

所以 get_temporary_buffer 可能是一个比你需要的更大的内存块,它被分配一次(也许有很多块准备好接受多个请求),每次你需要内存时,你只需要一个块。所以内存不会碎片化。

于 2012-01-06T03:04:31.310 回答