There are many design issues I have found with this, particularly with passing std::array<>
to functions. Basically, when you initialize std::array, it takes in two template parameters, <class T
and size_t size>
. However, when you create a function that requires and std::array
, we do not know the size, so we need to create template parameters for the functions also.
template <size_t params_size> auto func(std::array<int, params_size> arr);
Why couldn't std::array
take in the size at the constructor instead? (i.e.):
auto array = std::array<int>(10);
Then the functions would look less aggressive and would not require template params, as such:
auto func (std::array<int> arr);
I just want to know the design choice for std::array
, and why it was designed this way.
This isn't a question due to a bug, but rather a question why std::array<>
was designed in such a manner.
CodePudding user response:
std::array<T,N> var
is intended as a better replacement for C-style arrays T var[N]
.
The memory space for this object is created locally, ie on the stack for local variables or inside the struct itself when defined as a member.
std::vector<T>
in contrary always allocate it's element's memory in the heap.
Therefore as std::array
is allocated locally, it cannot have a variable size since that space needs to be reserved at compile time. std::vector
in the other hand has the ability to reallocate and resize since its memory is unbounded.
As a consequence, the big advantage of std::array
in terms of performance is that it eliminates that one level of indirection that std::vector
pays for its flexibility.
For example:
#include <cstdint>
#include <iostream>
#include <vector>
#include <array>
int main() {
int a;
char b[10];
std::vector<char> c(10);
std::array<char,10> d;
struct E {
std::array<char,10> e1;
std::vector<char> e2{10};
};
E e;
printf( "Stack address: %p\n", __builtin_frame_address(0));
printf( "Address of a: %p\n", &a );
printf( "Address of b: %p\n", b );
printf( "Address of b[0]: %p\n", &b[0] );
printf( "Address of c: %p\n", &c );
printf( "Address of c[0]: %p\n", &c[0] );
printf( "Address of d: %p\n", &d );
printf( "Address of d[0]: %p\n", &d[0] );
printf( "Address of e: %p\n", &e );
printf( "Address of e1: %p\n", &e.e1 );
printf( "Address of e1[0]:%p\n", &e.e1[0] );
printf( "Address of e2: %p\n", &e.e2);
printf( "Address of e2[0]:%p\n", &e.e2[0] );
}
Produces
Program stdout
Stack address: 0x7fffeb115ed0
Address of a: 0x7fffeb115eb0
Address of b: 0x7fffeb115ea6
Address of b[0]: 0x7fffeb115ea6
Address of c: 0x7fffeb115e80
Address of c[0]: 0x1cad2b0
Address of d: 0x7fffeb115e76
Address of d[0]: 0x7fffeb115e76
Address of e: 0x7fffeb115e40
Address of e1: 0x7fffeb115e40
Address of e1[0]:0x7fffeb115e40
Address of e2: 0x7fffeb115e50
Address of e2[0]:0x1cad2d0
Godbolt: https://godbolt.org/z/75s47T56f
CodePudding user response:
The main purpose of a C 11 std::array<>
is to be a decent replacement for C-style arrays []
, especially when they're declared with new
and dismissed with delete[]
.
The main goal here is to get an official, managed object that serves as an array, while maintaining as constant expressions everything that can be.
Principal issues with regular arrays is that since they're not actually objects, one cannot derivate a class from them (forcing you to implement iterators) and are a pain when you copy classes that uses them as object properties.
Since new
, delete
and delete[]
return pointers, you need each time either to implement a copy constructor that will declare another array them copy its content or maintaining your own dynamic reference counter on it.
From this perpective, std::array<>
is a good way to declare purely static arrays that will be managed by the language itself.