13

What does the C++ standard say about what sizeof(std::array<char, N>) should be (for some constant N)?

In a comment to a different question, it was mentioned that std::array is not always "stack allocated". The comment was in response to a different comment that speculated that putting a too large of a constant for std::array that is declared as a local variable could cause the program to abort due to insufficient resources for the "stack allocated" variable. I assume the followup comment meant that it would be possible for std::array to somehow switch to a dynamic allocation mode.

I could imagine that there could be some kind of SFINAE could be applied for an array size threshold that triggers a specialization of std::array that actually dynamically allocates an array and manages it. In that case, the sizeof(std::array<...>) might just be the size of a pointer. Is that allowed to happen?

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193
  • 1
    [Trying it](http://ideone.com/Y3ADE5) seems to suggest it's always `N`. – user2357112 Aug 07 '14 at 03:09
  • 3
    @user2357112: Yeah, I did try with g++ and clang++ and it seems to always be `N`, but that doesn't mean the standard wouldn't allow something different to happen. – jxh Aug 07 '14 at 03:11
  • 1
    [cppreference](http://en.cppreference.com/w/cpp/container/array) says "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." I think that implies the size is always N, though I don't know C++ well enough to say for certain. – user2357112 Aug 07 '14 at 03:11
  • @user657267: Thanks for finding that duplicate. That is pretty much exactly what I am asking, except I still don't have an explanation for what that comment meant. – jxh Aug 07 '14 at 04:07
  • 2
    @jxh : That comment meant that the array's data could be stored in a read-only memory segment, if e.g. you had `static std::array const x = {1, 2, 3};`, and read-only segments won't have the size limitations that stack allocation does. Dynamic allocation is _not_ an option for `std::array<>`. – ildjarn Aug 07 '14 at 05:07

1 Answers1

24

Obviously sizeof(std::array<char, N>) != N if N == 0. It also doesn't necessarily hold for N > 0. §23.3.2.1 [array.overview]/p1-2:

The header <array> defines a class template for storing fixed-size sequences of objects. An array supports random access iterators. An instance of array<T, N> stores N elements of type T, so that size() == N is an invariant. The elements of an array are stored contiguously, meaning that if a is an array<T, N> then it obeys the identity &a[n] == &a[0] + n for all 0 <= n < N.

An array is an aggregate (8.5.1) that can be initialized with the syntax

array<T, N> a = { initializer-list };

where initializer-list is a comma-separated list of up to N elements whose types are convertible to T.

§8.5.1 [dcl.init.aggr]/p1:

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

Since array is an aggregate type, it can't have a custom constructor that performs dynamic allocation, and it must store the elements directly since it must be able to be initialized from a initializer list using aggregate initialization. However, nothing in the standard prevents the implementation from adding extra stuff after its C-style array member, as long as array<T, N> a = { initializer-list }; has the defined semantics when the initializer-list contains at most N members. An implementation that looks like

template<typename T, size_t N>
struct array {
    //typedefs and member functions omitted

    T _Elems[N];
    double _Because_I_can;
};
// specialization for N == 0 case omitted

is perfectly legal. Therefore, there's no guarantee that sizeof(std::array<char, N>) == N.

T.C.
  • 133,968
  • 17
  • 288
  • 421