c++ 为什么需要std::get_temporary_buffer?

bf1o4zei  于 2023-06-07  发布在  其他
关注(0)|答案(6)|浏览(188)

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
Dr. Dobb's Journal, July 01, 1996中提出了一个用于实现算法的用例:
如果无法分配缓冲区,或者缓冲区小于请求的缓冲区,则算法仍然正常工作,只是速度变慢。

cqoc49vn

cqoc49vn1#

Stroustrup在《The C++ Programming Language》中说:
其思想是,系统可以保持多个固定大小的缓冲区准备用于快速分配,使得为 n 个对象请求空间可以产生用于多于 n 个对象的空间。然而,它也可能产生较少的收益,因此使用get_temporary_buffer()的一种方法是乐观地要求很多,然后使用碰巧可用的东西。
[...]由于get_temporary_buffer()是低级的,可能会被优化用于管理临时缓冲区,因此不应将其用作 newallocator::allocate() 的替代方案来获得长期存储。
他还开始介绍这两个函数:
算法通常需要临时空间来执行。
但似乎没有提供任何地方的“临时”或“长期”的定义。
"From Mathematics to Generic Programming"中的anecdote提到Stepanov在原始STL设计中提供了一个虚假的占位符实现,但是:
令他惊讶的是,几年后他发现所有提供STL实现的主要供应商仍然在使用这种可怕的实现。

r1zk6ea1

r1zk6ea12#

微软的标准库家伙说以下(在这里):

  • 你能解释一下什么时候使用'get_temporary_buffer'吗

它有一个非常特殊的目的。注意,它不像new(nothrow)那样抛出异常,但也不像new(nothrow)那样构造对象。
STL在内部使用stable_partition()等算法。当有像N3126 25.3.13 [alg.partitions]/11这样的魔法词时,就会发生这种情况:stable_partition()的复杂度为“At maximum(last

  • first)* log(last - first)swaps,但如果有足够的额外内存,则仅为线性数量的swaps。”当出现“如果有足够的额外内存”这句神奇的话时,STL使用get_temporary_buffer()来尝试获取工作空间。如果可以,那么它可以更有效地实现算法。如果不能,因为系统运行时非常接近内存不足(或者涉及的范围很大),算法可以退回到较慢的技术。

99.9%的STL用户永远不需要知道get_temporary_buffer()。

sqyvllje

sqyvllje3#

该标准规定它为最多n个元素分配存储空间。换句话说,您的示例可能返回一个仅能容纳5个对象的缓冲区。
不过,很难想象一个好的用例。如果您在一个内存非常有限的平台上工作,那么这可能是获得“尽可能多的内存”的一种方便方法。
但是在这样一个受限的平台上,我想您应该尽可能地绕过内存分配器,而使用内存池或您可以完全控制的东西。

jv4diomz

jv4diomz4#

std::get_temporary_buffer?的用途
The function在C++17中已被弃用,因此正确答案现在是“for no purpose,do not use it”。

ego6inou

ego6inou5#

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 ) );
  • respond* 可以小于 request
size_t require = 12;
int*   base    = static_cast<int*>( ::operator new( require*sizeof(int) ) );
assert( is_valid( base, base + require ) );
  • base* 的实际大小必须大于或等于 require
sbtkgmzw

sbtkgmzw6#

也许(只是猜测)这与内存碎片有关。如果你大量地分配和释放临时内存,但是每次你这样做,你都在分配临时内存之后,在释放临时内存之前分配一些长期的内存,你可能会得到一个碎片堆(我猜)。
所以get_temporary_buffer可以是一个比你需要的更大的内存块,它被分配一次(也许有很多块准备好接受多个请求),每次你需要内存时,你只需要得到其中一个块。这样记忆就不会支离破碎。

相关问题