I am trying to assign a C array to a C++ std::array.
How do I do that, the cleanest way and without making unneeded copies etc?
When doing
int X[8];
std::array<int,8> Y = X;
I get an compiler error: "no suitable constructor exists".
There is no conversion from plain array to std::array, but you can copy the elements from one to the other:
std::copy(std::begin(X), std::end(X), std::begin(Y));
Here's a working example:
#include <iostream>
#include <array>
#include <algorithm> // std::copy
int main() {
int X[8] = {0,1,2,3,4,5,6,7};
std::array<int,8> Y;
std::copy(std::begin(X), std::end(X), std::begin(Y));
for (int i: Y)
std::cout << i << " ";
std::cout << '\n';
return 0;
}
<array> guarantees you std::begin and std::end already; no need for <iterator>.<iterator> header, the function templates in 24.6.5 [overloads of std::begin and std::end] are available when any of the following headers are included: <array>, <deque>, <forward_list>, <list>, <map>, <regex>, <set>, <string>, <unordered_map>, <unordered_set>, and <vector>."std::copy is as unsafe as std::copy_n. Why do you think std::copy_n is safe?copy_n is safe. I was thinking using copy_n will force the programer to think about the correct size to copy, thus reducing the possibility of hidden overflow bugs. But this seems not correct as it depends. Thanks for pointing out.auto Y = std::to_array(X);.I know it's been a while, but maybe still useful (for somebody). The provided above solutions are great, however maybe you'd be interested in a less elegant, but possibly a faster one:
#include <array>
#include <string.h>
using namespace std;
double A[4] = {1,2,3,4};
array<double, 4> B;
memcpy(B.data(), A, 4*sizeof(double));
The array size can be determined in some other (more dynamic) ways when needed, here is just an idea. I have not tested the performance of both solutions.
The one proposed here requires to provide proper size, otherwise bad things can happen.
Edit:
Comments below made me do the tests and unless someone is really trying to squeeze max of the performance it's not worth it (test copied back and forth per loop):
B size:100000 tested copy vs memcpy on 100000 elements arrays with 100000 loop count:
** copy() = 9.4986 sec
** memcpy() = 9.45058 sec
B size:100000 tested copy vs memcpy on 100000 elements arrays with 100000 loop count:
** copy() = 8.88585 sec
** memcpy() = 9.01923 sec
B size:100000 tested copy vs memcpy on 100000 elements arrays with 100000 loop count:
** copy() = 8.64099 sec
** memcpy() = 8.62316 sec
B size:100000 tested copy vs memcpy on 100000 elements arrays with 100000 loop count:
** copy() = 8.97016 sec
** memcpy() = 8.76941 sec
sizeof(A) for the size argument in memcpymemcpy from the source. I beg you to always use the size of the destination object (B.size() in this case)In addition to @capatober's answer, here is a quick implemention if C++20 is not available:
template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array( T (&a)[N] ){
return [&]<std::size_t ... indexes>(std::index_sequence<indexes...>){
return std::array<std::remove_cv_t<T>, N>{ a[indexes]... };
}(std::make_index_sequence<N>{});
}
template< class T, std::size_t N >
constexpr std::array<std::remove_cv_t<T>, N> to_array( T (&&a)[N] ){
return [&]<std::size_t ... indexes>(std::index_sequence<indexes...>){
return std::array<std::remove_cv_t<T>, N>{ fwd(a)[indexes]... };
}(std::make_index_sequence<N>{});
}
Complete code: https://godbolt.org/z/asjMPx84q.
std::arrayhas no user defined constructors, because it was deemed important to keep its status as an aggregate type.