简体   繁体   中英

Does an unused STL container allocate memory?

Given the code:

class Foo {
  std::vector<int> items;
  std::map<int, int> dictionary;
};
  1. If nothing is ever added to the above vector or map, will either still allocate a block of buffer memory? (In other words, does buffer allocation always happen during container creation or can it be deferred until calls to functions like push_back?)

  2. Is there a standard for handling the timing of initial STL container buffer allocation or is that behavior allowed to vary between STL containers and compilers?

Note: This question is not about the extra bytes such containers would add to the size of class Foo.

(A related subset of this question with an emphasis on allocation size is Initial capacity of vector in C++ .)

C++ Reference With C++17 the default constructor is noexcept iff the allocator construction is noexcept . So it depends on the used allocator. In VS 2015 the standard constructor is noexcept .

Clarification: It means that if the allocator is no noexcept then no block of memory is allocated.

And for your second question: Same reference, its is O(1).

Standard doesn't say anything about it, but the implementation I've looked specifically at will do some pre-alocations for std::vector , and will not pre-allocate anything for std::map .

This actually once hit me prety hard, when I hade a huge container, which elements had a miniscule - no more than 10 elements, most entries had 0-sized vectors - vector in it. Default vector capacity in this implementation was 32, and '32 * sizeof(vector_element) * number_of_elements' happened to be extremely big.

As mentioned before, this is not well defined. However, you can just test it.

For example with gcc/linux. Make a simple program, compile it with -O0 -g and run it in gdb. Then

break main
run
break malloc
cont

Now simply run a backtrace on every malloc and you will see dynamic allocation. With my gcc 5.3.0, both empty containers do not allocate heap memory , this is done on the first push_back / operator[] .

Of course you should use your preferred debugger and break on your allocators underlying function, if that is not gdb / malloc .

Now if you think about the two cases. Would it make sense to pre-allocate memory in that case?

std::vector<int> foo;
foo.push_back(13);

Well, technically you might save a check for nullptr , but with the usual way to implement vectors as 3 pointers there is no need for an extra check.

But consider

std::vector<int> foo;
foo.reserve(100);

In this case it would be harmful to performance to pre-allocate.

I can find no argument for pre-allocation for a tree-structure such as map.

Please remember, this is a very specific optimization. Optimize for this only with good reason (benchmark!).

Note: You may want to read about small string optimization, a very common technique that is related but different.

  1. If nothing is ever added to the above vector or map, will either still allocate a block of memory for potential entries? (In other words, does entry allocation always happen during container creation or can it be deferred until calls to functions like push_back?)

That can happen, yes. It's actually a detail of the container implementation and not specified in the standard.

  1. Is there a standard for handling the timing of initial STL container allocation or is that behavior allowed to vary between STL containers and compilers?

You can defer the creation using eg a std::unique_ptr for the members, and create them with a call to a getter function.

It's worth noting that Microsoft's STL implementation currently does allocate in the default constructor for std::map and std::set . Godbolt example - note the call to operator new on line 8 of the assembly output.

And yes, this can absolutely impact performance. I only became aware of it after profiling some mysteriously slow code, when it turned out that the default constructor of a class with a rarely-used map member was dominating the run-time of the loop in question.

If, like me, you're not entirely thrilled by this implementation decision, I'll point out that Boost.Container 's counterparts do guarantee zero-allocation default construction.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM