89

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.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212

6 Answers6

48

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 [...]

Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
  • 14
    Looks like VC++'s implementation of this is simply a loop calling `operator new` with successively smaller arguments until the allocation succeeds. No special optimizations there. – jalf Jul 16 '10 at 12:43
  • 9
    Same with g++ 4.5 - seems it was well-intended but ignored by the vendors. – Georg Fritzsche Jul 19 '10 at 23:11
  • 4
    Sounds like they should have wrapped this functionality in a class called `crazy_allocator` – 0xbadf00d Jun 21 '14 at 13:10
  • But let's stay serious - Maybe one would be happy to allocate a lot of storage. What we now can do is asking the system to obtain that huge amount of storage - using `get_temporary_buffer`. However, if we receive less than the requested amount (what would be a real pity) we keep trying to do our work with the storage we've got. Might be better than to catch `bad_alloc` exceptions caused by the attempt to allocate more memory than available. However, the real usefulness stands and falls with a good implementation. – 0xbadf00d Jun 21 '14 at 13:10
  • 1
    @jalf It's deprecated in C++17 :) (according to [cppreference.com](http://en.cppreference.com/w/cpp/memory/get_temporary_buffer)). – 4LegsDrivenCat Aug 26 '16 at 12:46
  • @jalf that's the implementation Stepanov describes as bogus in the anecdote. – Philip Whitehouse Oct 29 '21 at 10:33
20

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().

Jeremy
  • 5,055
  • 1
  • 28
  • 44
9

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.

jalf
  • 243,077
  • 51
  • 345
  • 550
8

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".

Raedwald
  • 46,613
  • 43
  • 151
  • 237
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 ) );

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.

OwnWaterloo
  • 1,963
  • 14
  • 11
2

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.

Daniel Munoz
  • 1,865
  • 1
  • 14
  • 9
  • 1
    Very interesting thought. Although it seems to be currently implement as a *lets-just-do-something-that-works* by most implementations, this could very well be more tightly backed and integrated with the rest of the memory management routines. I vote for us actually ***expecting*** this to be suited for it, and Bjarnes comments seems to hint it too. – gustaf r Jan 07 '13 at 22:11
  • I've looked now for what Bjarne says about it and he says that it is designed for fast allocation without initialization. So it would be like a allocator-only (non initializer) void* operator new(size_t size), but that is faster to allocate, since it is pre allocated. – Daniel Munoz Feb 01 '13 at 00:21