1

Imagine a structure

struct A {
    int i;
    int arr[1000];
};

std::vector<A> vec;

I cannot find an answer to know if the array "arr" in my structure "A" will take up space on the stack or not at all. I these although the vector will allocate an array of "A" which will be on the heap and will not impact my stack but will my "arr" array impact my stack?

std::vector <A> vec1 (1000000);

std::vector<std::unique_ptr<A>> vec2 (1000000);

Will vec1 "destroy" my stack and better to use vec2?

Edit for the comment.

Why can vec1 allocate more elements than vec2?

#include <iostream>
#include <vector>
#include <memory>

struct A {
    int i;
    int arr[1000];
};

int main() {
  std::vector<std::unique_ptr<A>> vec1;
  std::vector<A> vec2;
  std::cout << vec1.max_size() << '\n' << vec2.max_size() << '\n';
}
6
  • 2
    std::vector<A> allocates it's backing storage on the heap so all the As in the std::vector will be on the heap. The stack size (sizeof) of any std::vector<T> is usually the same as the size of 2 pointers (implementation dependent). Commented Jul 28, 2021 at 7:38
  • 1
    The vector will be on the stack, but the data in the vector will be allocated on the heap. But I suppose that an implementation of std::vector might allocate data on the stack for small vector sizes, but I'm not sure if this is covered by the standard. Commented Jul 28, 2021 at 7:41
  • 1
    For the update look at sizeof(std::unique_ptr<A>) vs sizeof(A) - a vector is a container of "things" if the things are different sizes then you can hold more or less things in the total potentially available space. Also note the number of potential elements are stupidly large in both cases (64-bit). Commented Jul 28, 2021 at 7:47
  • vector::max_size isn't meaningful when you are targeting a 64-bit platform. It represents filling the whole address space with elements of the vector, and you can't buy one system with that much RAM. Commented Jul 28, 2021 at 8:26
  • 1
    @Jabberwocky Small buffer optimization is not possible for std::vector (in contrast to short string optimization for std::string, which is possible). There are some restrictions in the standard that disallows it. For instance, IIRC, swapping contents of two vectors may not invalidate iterators/pointer/references to their elements. Commented Jul 28, 2021 at 8:33

1 Answer 1

3

std::vector is one of AllocatorAwareContainers and default allocator use dynamic allocation (often called heap allocation, which is true for systems with heap-like memory model).

When using those two

std::vector<std::unique_ptr<A>> vec1;
std::vector<A> vec2;

both have own advantages and disadvantages. The vec1 offers arguably better time of resizing container itself because unique_ptr is quite small. vec2 offers instances of A with adjacent storage but resize time would be higher because of move operation used on each element. vec1 allocates only storage for pointers and not for the object itselves, by reaching that number you likely won't have memory left to create instances of A.

For lesser automatic storage (stack) footprint when using vec2 you might want to avoid creation of A temporary at all and use emplace_XXX methods to create instances of A right in vector's storage.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks but if everything is on the heap, why can vec1 have more elements than vec2? (see my edit)
@antho size of elements. maximum storage (in bytes) would be same. But that maximum size is usually comparable to maximum memory available to your program, so there is no deal, unless you're using some oddball implementation, where maximum size of vector is smaller.
@Martin.Martinsson Objects are not allocated. Their storage is allocated and objects are then initialized (constructed) there.
@Martin.Martinsson By allocation, I mean reserving a memory space for object storage (which may be on the heap, on the stack, in the data segment, etc.). Especially with std::vector, it is important to distinguish between allocation and initialization, since they are generally not performed at the same time (for instance, reserve allocates storage, push_back then initializes a new element). BTW, you may want to learn the difference between new-operator and new-expression. New-operator does not call any constructor.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.