7

Pardon my ignorance, it appears to me that std::array is meant to be an STL replacement for your regular arrays. But because the array size has to be passed as a template parameter, it prevents us from creating std::array with a size known only at runtime.

std::array<char,3> nums {1,2,3}; // Works.

constexpr size_t size = 3;
std::array<char,size> nums {1,2,3}; // Works.

const buf_size = GetSize();
std::array<char, buf_size> nums; // Doesn't work.

I would assume that one very important use case for an array in C++ is to create a fixed size data structure based on runtime inputs (say allocating buffer for reading files).

The workarounds I use for this are:

// Create a array pointer for on-the-spot usecases like reading from a file.
char *data = new char[size];
...
delete[] data;

or:

// Use unique_ptr as a class member and I don't want to manage the memory myself.
std::unique_ptr<char[]> myarr_ = std::unique_ptr<char[]>(new char[size]);

If I don't care about fixed size, I am aware that I can use std::vector<char> with the size pre-defined as follows:

std::vector<char> my_buf (buf_size);

Why did the designers of std::array choose to ignore this use case? Perhaps I don't understand the real usecase for std::array.

EDIT: I guess another way to phrase my question could also be - Why did the designers choose to have the size passed as a template param and not as a constructor param? Would opting for the latter have made it difficult to provide the functionality that std::array currently has? To me it seems like a deliberate design choice and I don't understand why.

xskxzr
  • 12,442
  • 12
  • 37
  • 77
Plasty Grove
  • 2,807
  • 5
  • 31
  • 42
  • What use-case did they miss? You presented two, and there's coverage for both in the standard library. – Ted Lyngmo Feb 15 '20 at 03:34
  • If the size of the array is determined at runtime, there is no fundamental difference between that, and `std::vector`. Because that's what `std::vector` is. – Sam Varshavchik Feb 15 '20 at 03:34
  • @TedLyngmo - Fixed size collection with size known only at runtime. – Plasty Grove Feb 15 '20 at 03:36
  • @SamVarshavchik - Yes - but `std::vector` is not fixed size. – Plasty Grove Feb 15 '20 at 03:36
  • @PlastyGrove How is that missed? That's exactly what's offered by `std::array`. – Ted Lyngmo Feb 15 '20 at 03:37
  • 3
    He wants exactly `std::dynarray` http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2013/n3662.html – Brandon Feb 15 '20 at 03:37
  • 1
    So do you want to know why there is not an array type container with size fixed at runtime? Or do you want to know what the advantages are of the `std::array` having size fixed at compile time? – Galik Feb 15 '20 at 03:38
  • @TedLyngmo - My bad, fat fingers, corrected it. I meant fixed size collection with size known at runtime. – Plasty Grove Feb 15 '20 at 03:38
  • @Brandon Ah .. that's sort of useless in C++, isn't it? What's the purpose? (with risk of getting in to opinion territory) – Ted Lyngmo Feb 15 '20 at 03:38
  • 5
    Just pretend that `std::vector`'s size cannot be changed after it is constructed. Problem solved. – Sam Varshavchik Feb 15 '20 at 03:41
  • @TedLyngmo no idea.. but he can use `alloca` or `variable length array` I guess.. It'll accomplish the same thing. Maybe he wants the array to be stack allocated instead of heap allocated but with a runtime size. – Brandon Feb 15 '20 at 03:41
  • @SamVarshavchik - I do pretend it can't be changed often and I do use `std::vector`. But I wasn't sure if I'm missing something fundamental about `std::array`. – Plasty Grove Feb 15 '20 at 03:42

3 Answers3

9

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.

Community
  • 1
  • 1
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • But for the designers of `std::array`, would it really have been so hard to have all the features you specified above AND have the size parameter passed to the constructor instead of as a template param? That seems trivial to the talented C++ developers behind the STL to implement, but yet they chose not to do it. Why? – Plasty Grove Feb 15 '20 at 03:44
  • 1
    @PlastyGrove, if size parameter is passed to the constructor then it's `std::vector` :-). In C, they have something similar known as variadic arrays. If the size is known only at runtime, then the compiler's optimizer cannot take the full advantage of creating that variable on stack memory, which is more efficient. Instead, the runtime size has to be passed on to the free-store (heap memory) for creating a runtime array. This is a slight performance degradation for no good reason. `std::array` is merely a wrapper around the C-style fixed arrays. to provide type-safety with useful interfaces. – iammilind Feb 15 '20 at 04:28
  • I see, so there's no way to create an array on the stack unless I pass the parameter as a template param at compile time? – Plasty Grove Feb 15 '20 at 04:41
  • 1
    Stack-allocation implies that the data for the array is stored in the object itself. But that would mean that `sizeof(runtime_sized_array)` couldn't be a compile-time constant, which would break a lot of things. For example, how would you stack-allocate a `std::optional>`? How would you implement a `std::vector>`? Or even a `runtime_sized_array two_arrays[2]{ runtime_sized_array(5), runtime_sized_array(7) }`? If you had `runtime_sized_array* p`, what would `p++` do? – Raymond Chen Feb 15 '20 at 04:48
  • @RaymondChen - That makes sense, thanks for explaining. – Plasty Grove Feb 15 '20 at 05:04
  • @PlastyGrove, array on stack memory is created only if the size is known at compile time. For that matter anything on stack memroy is created whose size is deterministic (viz. known beforehand). For runtime sizes, there is a heap memory (free store). – iammilind Feb 15 '20 at 05:46
  • You've missed a main benefit of `std::array` (and vector): they are [Regular types](https://www.modernescpp.com/index.php/c-core-guidelines-regular-and-semiregular-typs) (for Regular element types) – Caleth Sep 08 '20 at 11:20
  • Its quite possible to allocate a `std::vector` on the stack using a custom allocator. – Sebastian Hoffmann Sep 08 '20 at 11:52
3

The two main reasons I understand are:

  • std::array implements STL's interfaces for collection-types, allowing an std::array to be passed as-is to functions and methods that accept any STL iterator.
  • To prevent array pointer decay... (below)

...this is the preservation of type information across function/method boundaries because it prevents Array Pointer Decay.

Given a naked C/C++ array, you can pass it to another function as a parameter argument by 4 ways:

void by_value1   ( const T* array )
void by_value2   ( const T array[] )
void by_pointer  ( const T (*array)[U] )
void by_reference( const T (&array)[U] )
  • by_value1 and by_value2 are both semantically identical and cause pointer decay because the receiving function does not know the sizeof the array.
  • by_pointer and by_reference both requires that U by a known compile-time constant, but preserve sizeof information.

So if you avoid array decay by using by_pointer or by_reference you now have a maintenance problem every time you change the size of the array you have to manually update all of the call-sites that have that size in U.

By using std::array it's taken care of for you by making those functions template functions where U is a parameter (granted, you could still use the by_pointer and by_reference techniques but with messier syntax).

...so std::array adds a 5th way:

template<typename T, size_t N>
void by_stdarray( const std::array<T,N>& array )
Dai
  • 141,631
  • 28
  • 261
  • 374
0

std::array is a replacement for C-style arrays.

The C++ standards don't allow C-style arrays to be declared without compile-time defined sizes.

Sid S
  • 6,037
  • 2
  • 18
  • 24
  • 1
    `std::array` is not a replacement, but a wrapper around C-style array. C-style array is a language feature, while `std::array` is a library util which encapsulates it underneath. – iammilind Feb 15 '20 at 04:31
  • @SidS - C++ standards do allow C-style arrays to be declared with runtime defined sizes. `int s=3; int myarr[s]{1,2,3};` works perfectly in `C++` – Plasty Grove Feb 15 '20 at 04:44
  • 3
    @PlastyGrove No, variable length arrays are [not allowed in C++](https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard). They're a C99 feature that **some compilers** allow in C++ code. They're not standard and not portable. – Blastfurnace Feb 15 '20 at 04:53
  • @Blastfurnace - Wow, you're right. The code above works with `g++`, but fails with `clang++` saying 'variable-sized object may not be initialized' – Plasty Grove Feb 15 '20 at 04:59
  • 1
    @PlastyGrove Use the `-Wpedantic` compiler option with g++ or clang to see their [warning about VLAs](https://godbolt.org/z/3FVjcb). – Blastfurnace Feb 15 '20 at 05:02
  • @Blastfurnace - You're right, thanks for pointing it out. I think this makes total sense now and I understand why `std::array` needs to have compile time size. – Plasty Grove Feb 15 '20 at 05:06