Is the Size of Std::Array Defined by Standard

Is the size of std::array defined by standard

It's nearly required. Specifically, §23.3.2.1/2 says:

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.

Since it's an aggregate, it can't use any sort of constructor to convert the data in the initializer-list to the correct format. That really only leaves one possibility: about the only thing it can store are the values themselves.

I suppose it would be possible for an std::array to store some sort of auxiliary data following the specified data, such as extra memory set to some predefined value, so if you write past the end of the array, you'd probably change that data. The compiler/run-time would then check those values at shut-down, and if you'd changed the values, report your code's undefined behavior.

It's also possible that a compiler could do padding/alignment differently for an std::array than for a built-in array. One obvious example for which this could even be desirable would be to support super-alignment requirements, such as data for use with Intel's SSE instructions. A built-in array can't support super-alignment, but I think the specification of std::array might be barely loose enough to allow it.

Bottom line: without getting into questions of how many possibilities might exist, it's pretty clear that std::array doesn't necessarily have to follow the rule you're asking about.

Is the size of std::array T, N guaranteed to be equal to the size of T[N]?

No.

The only guarantees we get with std::array<T, N> are that:

  • size() is N;
  • &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 };

There is nothing stopping the implementor from adding a trailing member, though I know of no reason why one would.

In C++ what is the point of std::array if the size has to be determined at compile time?

Ease of programming

std::array facilitates several beneficial interfaces and idioms which are used in std::vector. With normal C-style arrays, one cannot have .size() (no sizeof hack), .at() (exception for out of range), front()/back(), iterators, so on. Everything has to be hand-coded.

Many programmers may choose std::vector even for compile time known sized arrays, just because they want to utilize above programming methodologies. But that snatches away the performance available with compile time fixed size arrays.

Hence std::array was provided by the library makers to discourage the C-style arrays, and yet avoid std::vectors when the size is known at the compile time.

What is the type of the size of std::array and if the size is bigger than what's available on the stack, does it throw an exception?

What is the type of the size of std::array

It is std::size_t which is an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object.

1 - why is this happening?

According to the message, this is happening because "total size of array must not exceed 0x7fffffff bytes". This appears to be a limitation of that particular language implementation.

For what it's worth, the C++ standard suggests 0x40000 as a guideline recommendation for minimum limit for the maximum size of an object. 0x7fffffff exceeds that recommendation by a large margin. On a x86-64 Linux system, the maximum size limit for an object is 0x7fffffffffffffff instead.

Is the array allocated on the heap if it's big for example?

Where memory for an object is allocated depends on the type of storage you use, and on the implementation of the language. The size of the object typically does not affect this. std::array never allocates any dynamic memory.

what happens if the size of the array does exceed the size of the stack?

It does not matter how the size of execution stack is exceeded. The language doesn't specify what happens, nor does it acknowledge the existence of a "stack". It is an implementation specific concept. Thus, what happens depends on the implementation. If you're lucky, the program crashes. If you're unlucky, your secrets leak to the hackers.

What is the sizeof std::array char, N ?

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.

Is there a standard C++ class for arrays with fixed run-time-determined size?

Allocate the memory using an std::unique_ptr<T[]> like you suggested, but to use it - construct an std::span (in C++20; gsl::span before C++20) from the raw pointer and the number of elements, and pass the span around (by value; spans are reference-types, sort of). The span will give you all the bells and whistles of a container: size, iterators, ranged-for, the works.

#include <span>
// or:
// #include <gsl/span>

int main() {

// ... etc. ...

{
size_t size = 10e5;
auto uptr { std::make_unique<double[]>(size) };
std::span<int> my_span { uptr.get(), size };
do_stuff_with_the_doubles(my_span);
}

// ... etc. ...
}

For more information about spans, see:

What is a "span" and when should I use one?

comparison operator for std::array

Is there a fundamental reason why the standard library does not define operator== as in the code above?

Most fundamental reason that standard library doesn't define it is: Such operator== wasn't proposed. This is the proposal to add the wrapper into the standard. It does not contain rationale for not providing comparison between different instances of the template. There's no evidence in the document that such operator had been even considered.



Related Topics



Leave a reply



Submit