38

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".

Gizmo
  • 1,990
  • 1
  • 24
  • 50
  • 3
    Note that `std::array` has no user defined constructors, because it was deemed important to keep its status as an aggregate type. – Benjamin Lindley Oct 06 '14 at 15:44

3 Answers3

39

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;
}
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 2
    `` guarantees you `std::begin` and `std::end` already; no need for ``. – T.C. Oct 06 '14 at 15:44
  • 1
    @T.C. I can't find that, at least not in the C++11 standard. Do you have a reference? – juanchopanza Oct 06 '14 at 16:43
  • 4
    @juanchopanza 24.6.5/1: "In addition to being available via inclusion of the `` 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: ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, and ``." – Casey Oct 06 '14 at 17:39
  • std::copy is unsafe, you should use std::copy_n as much as possible. – stupidlearner Mar 25 '17 at 17:58
  • 1
    @stupidlearner `std::copy` is as unsafe as `std::copy_n`. Why do you think `std::copy_n` is safe? – Rakete1111 Apr 28 '17 at 17:18
  • 1
    @Rakete1111 I didn't say `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. – stupidlearner Apr 30 '17 at 02:31
  • You can always guarantee a size match by taking the arrays by reference as function parameters, and use template metamagic to guarantee that the `std::array`'s size is at least as large as the raw array's, @stupidlearner. – Justin Time - Reinstate Monica Aug 28 '19 at 17:14
  • @JustinTime could you give an example? – Michel Feinstein Sep 04 '19 at 23:51
  • [Here you go](https://wandbox.org/permlink/EXDhvx2uxkrc7nrG), @mFeinstein. Just a quick example, it could easily be turned into, e.g., a trait that takes the arrays' types and inherits from `std::integral_constant= N>`. – Justin Time - Reinstate Monica Sep 05 '19 at 00:40
  • Thanks @JustinTime, depite years in C, I am still too much of a newbie in C++ to understand it all though. – Michel Feinstein Sep 05 '19 at 00:50
  • You're welcome, @mFeinstein. Basically, `std::array a` is essentially just a struct that bundles a C `T a[N]` with the usual C++ container interface, templates are Mad Libs (generic programming, in this case used basically as localised, safer macros; `T` is a type, and `N` & `NPP` are `size_t`s), `type&` is a reference to `type` (like a pointer, but without pointer syntax), `constexpr` is a "this is a constant expression" keyword (for functions, tells the compiler to execute calls at compile time if possible; for `if constexpr`, lets the compiler remove a check if the correct branch... – Justin Time - Reinstate Monica Sep 05 '19 at 01:10
  • `cobstexpr` was the new one for me, thanks for the explanation! – Michel Feinstein Sep 05 '19 at 01:14
  • ...is known at compile time (such as comparing `N` and `NPP`, since template parameters are part of the function signature, and thus known while compiling a specialisation of `compareSize()`; in this case, because of the way it's used in a templated function, it lets the compiler replace the entire function body with just the applicable return statement); for variables, makes them compile-time constants (kinda like macros with type information)), `[[nodiscard]]` is an attribute that tells the compiler to whine if you ignore the return value, and `T (&)[N]` is syntax for passing... – Justin Time - Reinstate Monica Sep 05 '19 at 01:17
  • ...the entire array by reference (can also be done with pointers in both C and C++, but isn't as useful in C due to not having as much generic support). [About `if constexpr`, the template `compareSize` will be used to make two functions; due to `if constexpr`, `compareSize()` is just `{ return "big enough"; }`, and `compareSize()` is just `{ return "too little"; }`.] And you're quite welcome, @mFeinstein, although it may be best to move to chat if we continue this. ;P – Justin Time - Reinstate Monica Sep 05 '19 at 01:21
  • Haahha indeed chat would be better – Michel Feinstein Sep 05 '19 at 01:24
16

C++20 has std::to_array function

So, the code is

int X[8];
std::array<int, 8> Y = std::to_array(X);

https://godbolt.org/z/Efsrvzs7Y

capatober
  • 351
  • 2
  • 5
3

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

  • 2
    It's simpler and more robust to use `sizeof(A)` for the size argument in `memcpy` – SomeWittyUsername Nov 13 '20 at 06:09
  • 3
    Quite the bold statement "faster one" and one sentence later "Not tested for performance". AFAIK: https://stackoverflow.com/a/4707028/2548287 => std::copy is for the compiler the same as memcpy (i.e. std::copy calls memcpy, or just gets vectorized). – Gizmo Nov 13 '20 at 07:39
  • 1
    All valid comments. As I wrote it is "possibly" faster, as I have not test it. But your comment made me do the test, and the difference is not worth the ugliness of using "memcpy" - they almost the same, with "memcpy" being just slightly faster. – Radoslaw Garbacz Nov 14 '20 at 16:40
  • 1
    @SomeWittyUsername OMG! Please never calculate the size argument of `memcpy` from the source. I beg you to always use the size of the destination object (`B.size()` in this case) – Ves Dec 09 '21 at 09:03
  • @Ves If you're concerned about possible target buffer overflow there are other ways to deal with it and they are out of scope for this question. Your suggestion just switches the possible target buffer overflow with source buffer overflow. – SomeWittyUsername Dec 09 '21 at 22:24