为什么需要 std::get_temporary_buffer?

发布于 2024-09-09 23:35:57 字数 820 浏览 12 评论 0 原文

我应该出于什么目的使用 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,1996 年 7 月 1 日 用于实现算法:

如果无法分配缓冲区,或者缓冲区小于请求的缓冲区,算法仍然可以正常工作,只是速度会变慢。

For what purpose I should use std::get_temporary_buffer? Standard says the following:

Obtains a pointer to storage sufficient to store up to n adjacent T objects.

I thought that the buffer will be allocated on the stack, but that is not true. According to the C++ Standard this buffer is actually not temporary. What advantages does this function have over the global function ::operator new, which doesn't construct the objects either. Am I right that the following statements are equivalent?

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

Does this function only exist for syntax sugar? Why is there temporary in its name?


One use case was suggested in the Dr. Dobb's Journal, July 01, 1996 for implementing algorithms:

If no buffer can be allocated, or if it is smaller than requested, the algorithm still works correctly, It merely slows down.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

澜川若宁 2024-09-16 23:35:57

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

这个想法是,系统可以保留许多固定大小的缓冲区以供快速分配,以便为 n 个对象请求空间可能会产生超过 n 个对象的空间。然而,它也可能产生较少的结果,因此使用 get_temporary_buffer() 的一种方法是乐观地请求大量数据,然后使用可用的数据。
[...] 由于 get_temporary_buffer() 是低级的,并且可能会针对管理临时缓冲区进行优化,因此不应将其用作 new >allocator::allocate() 用于获取长期存储。

他还首先介绍了这两个函数:

算法通常需要临时空间才能正常运行。

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

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

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

Stroustrup says in "The C++ Programming Language" (§19.4.4, SE):

The idea is that a system may keep a number of fixed-sized buffers ready for fast allocation so that requesting space for n objects may yield space for more than n. It may also yield less, however, so one way of using get_temporary_buffer() is to optimistically ask for a lot and then use what happens to be available.
[...] Because get_temporary_buffer() is low-level and likely to be optimized for managing temporary buffers, it should not be used as an alternative to new or allocator::allocate() for obtaining longer-term storage.

He also starts the introduction to the two functions with:

Algorithms often require temporary space to perform acceptably.

... but doesn't seem to provide a definition of temporary or longer-term anywhere.

An anecdote in "From Mathematics to Generic Programming" mentions that Stepanov provided a bogus placeholder implementation in the original STL design, however:

To his surprise, he discovered years later that all the major vendors that provide STL implementations are still using this terrible implementation [...]

笑,眼淚并存 2024-09-16 23:35:57

微软的标准库人员说了以下内容(此处):

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

它有一个非常特殊的目的。请注意,它不会抛出
异常,例如 new (nothrow),但它也不构造对象,
与 new (no throw) 不同。

它由 STL 在 stable_partition() 等算法中内部使用。
当存在诸如 N3126 25.3.13 之类的魔术词时,就会发生这种情况
[alg.partitions]/11:stable_partition() 的复杂性“最多(最后

  • first) * log(last - first) 交换,但如果有足够的额外内存,则只有线性数量的交换。”当魔术词“如果有
    出现足够的额外内存”,STL 使用 get_temporary_buffer() 来
    尝试获得工作空间。如果可以,那么它可以实现
    算法更高效。如果不能的话,因为系统正在运行
    危险地接近内存不足(或者涉及的范围很大),
    该算法可以回退到较慢的技术。

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

Microsoft's standard library guy says the following (here):

  • Could you perhaps explain when to use 'get_temporary_buffer'

It has a very specialized purpose. Note that it doesn't throw
exceptions, like new (nothrow), but it also doesn't construct objects,
unlike new (nothrow).

It's used internally by the STL in algorithms like stable_partition().
This happens when there are magic words like N3126 25.3.13
[alg.partitions]/11: stable_partition() has complexity "At most (last

  • first) * log(last - first) swaps, but only linear number of swaps if there is enough extra memory." When the magic words "if there is
    enough extra memory" appear, the STL uses get_temporary_buffer() to
    attempt to acquire working space. If it can, then it can implement the
    algorithm more efficiently. If it can't, because the system is running
    dangerously close to out-of-memory (or the ranges involved are huge),
    the algorithm can fall back to a slower technique.

99.9% of STL users will never need to know about get_temporary_buffer().

暮光沉寂 2024-09-16 23:35:57

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

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

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

The standard says it allocates storage for up to n elements.
In other words, your example might return a buffer big enough for 5 objects only.

It does seem pretty difficult to imagine a good use case for this though. Perhaps if you're working on a very memory-constrained platform, it's a convenient way to get "as much memory as possible".

But on such a constrained platform, I'd imagine you'd bypass the memory allocator as much as possible, and use a memory pool or something you have full control over.

末骤雨初歇 2024-09-16 23:35:57

For what purpose I should use std::get_temporary_buffer?

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

温馨耳语 2024-09-16 23:35:57
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

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 may be less than request.

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

the actual size of base must greater or equal to require.

给妤﹃绝世温柔 2024-09-16 23:35:57

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

因此 get_temporary_buffer 可能旨在成为一个比您需要的内存块更大的内存块,该内存块被分配一次(也许有许多块准备好接受多个请求),并且每次您需要内存时,您只需获取其中一个大块。这样内存就不会碎片化。

Perhaps (just a guess) it has something to do with memory fragmentation. If you heavily keep allocating and deallocating temporal memory, but each time you do it you allocate some long-term intended memory after allocating the temp but before deallocating it, you may end up with a fragmented heap (I guess).

So the get_temporary_buffer could be intended to be a bigger-than-you-would-need chunk of memory that is allocated once (perhaps there are many chunks ready for accepting multiple requests), and each time you need memory you just get one of the chunks. So the memory doesn't get fragmented.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文