Does std::array<> guarantee allocation on the stack only?
Asked Answered
G

2

72

Is std::array<int,10> (without myself using new) guaranteed to be allocated in the stack rather then the heap by the C++-Standard?

To be clear, I do not mean new std::array<int, 10>. I mainly wonder, if the standard library is allowed to use new inside its implementation.

Giff answered 17/9, 2016 at 15:0 Comment(2)
I could think of a related question, when putting std::array inside a struct, does it extend the size of the struct with the size of the content of the array, or (as do vectors) extend the size of the struct with the size of mere metadata?Prokopyevsk
@把友情留在无盐 the size of the struct is such that it can hold the array itself. i.e. in struct S { std::array<int8_t, 10> a; };, sizeof(S) == 10Footslog
U
32

I could not find more explicit answer in the standard, but [array.overview]/2:

An array is an aggregate ([dcl.init.aggr]) that can be list-initialized with up to N elements whose types are convertible to T.

And [dcl.init.aggr]/1:

An aggregate is an array or a class (Clause [class]) with

  • no user-provided, explicit, or inherited constructors ([class.ctor]),

...

That about covers it. No way an aggregate could allocate memory dynamically (or perhaps, do anything at all at its own during the construction). There's only an implicitly-declared trivial constructor.

Of course, if you new std::array<...>, you get an array on "the heap".


Some may be more satisfied by what we can get on cppreference:

std::array is a container that encapsulates fixed size arrays.

This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member.


Thirdly, std::array was introduced in C++11. Why? For example, to complement std::vector in some ways, like usage in constexpr functions, where dynamic allocation is not allowed.

Unsteady answered 17/9, 2016 at 15:8 Comment(4)
+1 In other words, you get the same guarantees as template <class N, size_t N> struct array { T elems[N]; }; w.r.t. layout (elems does not actually exist).Gracious
@towi: Note that C++ doesn't really have the concept of a stack or heap. Usually we get what you mean, but you asked "by the c++ standard". You get the same guarantees as the example I gave above; how this gets allocated is up to your implementation. (In theory I could write a dumb compiler that doesn't use the stack at all, and dynamically allocates everything.)Gracious
@Gracious You know, I totally missed that! "no concept of stack and heap", really? Also no of "dynamically" or "statically" allocated? You may be right, quick search in Std agrees to that. I guess the definition if new and spec of <new> describing dynamic allocation specifically made me miss the absence of a static allocation specification. Given your dumb compiler, I wonder if one could be possible doing everything on stack. No probably not, how could I support new? But that's a different question.Giff
@Giff You can do so by overriding operator new() and having it use your own static allocation (of some size of your choosing). Or better yet, simply provide a static allocator.Lumpy
F
64

TL;DR: yes, it is on the stack.


The longer story:

C++ has no concept of stack or heap. Those are implementation details, and there is at least one platform that does not use a traditional stack (but rather linked list of heap allocations for it).

It has automatic storage and the free store. new accesses the free store, and variables "on the stack" go into automatic storage.

In practice, in order to allocate things on the free store, you have to risk an out of memory exception. So the general rule is things that guarantee they do not throw must be using automatic storage. array makes this guarantee (except whatever is in it can throw, naturally). It is also an aggregate of plain old data, effectively forced to look like:

template<class T,std::size_t N>
struct array {
  T __no_fixed_name__[N];
  // non-constructor/destructor methods omitted as they are noise at this point
};

In theory it could be implemented by the compiler via magic that is not actual C++, but there is no need for that, so nobody bothers.

So in conclusion: yes, std::array is on the stack.

Flavopurpurin answered 17/9, 2016 at 17:12 Comment(6)
Can you point me to that interesting stackless implementation? Sounds frightfully interesting. (These things are never TL;DR...)Giff
@Giff sorry, I am aware of it existing, that is all.Flavopurpurin
@Giff IBM mainframes, apparently. A bit more detail in the comments on Jerry Coffin's answer there.Much
i would like to point out that std::array template signature has two parameters. the first is the type and the second is the number of elements. important to note is there is no third template parameter for the allocator.Featurelength
Knowing that std::array resides on the stack is important IMO because then you can avoid declaring a large std::array on the stack and crashing your program.Featurelength
I once used a C system where automatic variables were not stored in a stack. Instead, space in the static data area was used; it defaulted to allowing 3 copies of each function's variables to handle re-entrancy but if you entered more than 3 times you were toastGarrison
U
32

I could not find more explicit answer in the standard, but [array.overview]/2:

An array is an aggregate ([dcl.init.aggr]) that can be list-initialized with up to N elements whose types are convertible to T.

And [dcl.init.aggr]/1:

An aggregate is an array or a class (Clause [class]) with

  • no user-provided, explicit, or inherited constructors ([class.ctor]),

...

That about covers it. No way an aggregate could allocate memory dynamically (or perhaps, do anything at all at its own during the construction). There's only an implicitly-declared trivial constructor.

Of course, if you new std::array<...>, you get an array on "the heap".


Some may be more satisfied by what we can get on cppreference:

std::array is a container that encapsulates fixed size arrays.

This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member.


Thirdly, std::array was introduced in C++11. Why? For example, to complement std::vector in some ways, like usage in constexpr functions, where dynamic allocation is not allowed.

Unsteady answered 17/9, 2016 at 15:8 Comment(4)
+1 In other words, you get the same guarantees as template <class N, size_t N> struct array { T elems[N]; }; w.r.t. layout (elems does not actually exist).Gracious
@towi: Note that C++ doesn't really have the concept of a stack or heap. Usually we get what you mean, but you asked "by the c++ standard". You get the same guarantees as the example I gave above; how this gets allocated is up to your implementation. (In theory I could write a dumb compiler that doesn't use the stack at all, and dynamically allocates everything.)Gracious
@Gracious You know, I totally missed that! "no concept of stack and heap", really? Also no of "dynamically" or "statically" allocated? You may be right, quick search in Std agrees to that. I guess the definition if new and spec of <new> describing dynamic allocation specifically made me miss the absence of a static allocation specification. Given your dumb compiler, I wonder if one could be possible doing everything on stack. No probably not, how could I support new? But that's a different question.Giff
@Giff You can do so by overriding operator new() and having it use your own static allocation (of some size of your choosing). Or better yet, simply provide a static allocator.Lumpy

© 2022 - 2024 — McMap. All rights reserved.