57

I often find myself wanting to copy the contents of arrays that have a constant size, I usually just write something along the lines of:

float a[4] = {0,1,2,3};
float b[4];

for(int i=0; i<4; i++){
    b[i]=a[i];
}

As of lately, I am writing a linear calculus library for educational purposes, and I was wondering if there was a better way to do it.

The first thing that came to my mind, was using memcpy:

memcpy(b, a, sizeof(float) * 4);

But this seems very c-like and error prone to me. I like having my errors at compile time, and this can get ugly for data types with non-trivial copy constructors, or if I forget to multiply with sizeof(datatype).

Since I am writing a math library that I am going to use intensively, performance is very important to me. Are the compilers today smart enough to understand that the first example is just copying a chunk of memory and optimize it to be as efficient as the second solution?

Perhaps there is a function in the standard library that can help me? Something new in c++11? Or should I just create a macro or a template function?

1
  • 1
    "But this seems very c-like and error prone to me" - What's error prone about it? You know the size, you know the memory is valid... no error will occur. If you are dealing with POD types I would always just use memcpy. Commented Sep 13, 2012 at 0:37

5 Answers 5

83

If you use std::array instead of a built-in array (which you should), it becomes very simple. Copying an array is then the same as copying any other object.

std::array<float,4> a = {0,1,2,3};
std::array<float,4> b = a;
5
  • 1
    +1 this is clearly the way to go in C++11 (and not the std::copy() methods, as they use run-time size and hence are less prone to optimisation using than compile-time size, which is the very point of using arrays (instead of vector) in the first place
    – Walter
    Commented Sep 8, 2012 at 20:38
  • 1
    @Walter: Actually, the methods using std::copy, as presented by Mysticial and hjbabs, both use a compile time constant. So they can be optimized in the exact same ways. Commented Sep 8, 2012 at 21:39
  • 4
    @BenjaminLindley you didn't get my point. The std::copy() function template accepts the size as a run-time constant. If that number is known at compile time, then the compiler may do some optimisation. With std::array<>::operator= this is spelled out at compile time: there is not run-time-size-dependent code to be optimised (or not). I prefer not relying on the compiler to do these types of optimisations.
    – Walter
    Commented Sep 9, 2012 at 9:33
  • 2
    I'm a little confused. This question is about C style arrays. Why is the solution using std::arrays? To me this should definitely NOT be the canonical answer to the question.
    – user650261
    Commented Dec 1, 2016 at 20:44
  • 5
    @user650261: The question is not about C-style arrays. It is about constant sized arrays. One way to have a constant size array is to use a c-style array. Another way, which the OP apparently was not aware of before asking the question, is std::array. And as it turns out, std::array is superior for that purpose, in almost every single way. And in particular, it is much better at solving the very problem the OP was actually concerned about. Commented Dec 1, 2016 at 20:55
58

The C++03 way

Use std::copy():

float a[4] = {0,1,2,3};
float b[4];

std::copy(a,a + 4, b);

That's about as clean as it gets.

The C++11 way

std::copy(std::begin(a), std::end(a), std::begin(b));

If you can use std::array

With std::array you just do simple assignment:

std::array<float,4> a = {0,1,2,3};
auto b = a;
9
  • 6
    To avoid things quietly breaking if you change the array size, I suggest std::copy(a, a + sizeof(a)/sizeof(a[0]), b);. Even better, wrap the sizeof() junk in a macro -- or even betterer, use a function template instead: template <typename T, size_t N> size_t size((T&)[N]) { return N; } Commented Sep 8, 2012 at 7:29
  • 20
    @j_random_hacker: In C++11, std:copy(std::begin(a), std::end(a), std::begin(b)).
    – GManNickG
    Commented Sep 8, 2012 at 8:39
  • 1
    @GManNickG: So they finally added generic begin() and end() in C++11? Wonderful! (And such an obvious thing... How did C++03 miss it?!) I can stop carting around my homebrewed ones :) Commented Sep 8, 2012 at 8:46
  • Interesting. I also didn't know you could use std::begin/end on arrays now. :)
    – Mysticial
    Commented Sep 8, 2012 at 8:51
  • 4
    Downvoters care to comment? It's hard to improve something if I don't know what's wrong.
    – Mysticial
    Commented Sep 13, 2012 at 0:20
22

For interested in C++03 (and also C) solution - always use struct containing an array instead of solely array:

struct s { float arr[5]; };

Structs are copyable by default.

Its equivalent in C++11 is,already mentioned, std::array<float,5>;

2
  • 2
    Good point about c++03 struct wrapping. I need to remember this better :)
    – sehe
    Commented Sep 13, 2012 at 0:32
  • 1
    thank you this is the info i was looking for from google. Because nothing much is said about assignation of std/boost::array. its default generated, therefore the standard dictates behavior. but chapters about aggregate are hard to read in santardese legal jargon.
    – v.oddou
    Commented Apr 23, 2015 at 5:11
7

Below method works for usual arrays as well std:array.

float a[4] = {0,1,2,3};
float b[4];

std::copy(std::begin(a), std::end(a), b);
4
  • 2
    Note sure why downvoting. This works, its indeed preferred way in C++, applicable to usual arrays as well and I use it all the time. Commented Nov 28, 2017 at 5:54
  • 1
    @Shitai Shah, preferred or not it's ugly and easy to error prone.
    – CodingLab
    Commented Mar 25, 2020 at 12:50
  • 2
    @CodingLab, disagree. My code is littered with this and it is a fine solution if you are using c-style arrays which are abundant out there in the real world. Commented Mar 28, 2020 at 18:22
  • How can this be uglier than std::array<float,4> a = {0,1,2,3}; ? I prefer this and use it in both C and C++. Looks cool and simple. Unfortunately, older c++ versions (< C++11) don't support this for member initialisation within class declarations. Commented Mar 17, 2023 at 12:30
4
#include <algorithm>
std::copy_n(a, 4, b)
5
  • that can't be the most efficient way in case of arrays, as the number of elements is a run-time argument instead of a compile-time one.
    – Walter
    Commented Sep 8, 2012 at 20:34
  • 2
    @Walter: you are right, std::array should be used for constant size arrays
    – hjbabs
    Commented Sep 9, 2012 at 2:02
  • 1
    @Walter All answers here depend on quality of compiler inliner and memcpy intrinsic. copy_n here will probably transformed to one SIMD instruction. Commented Apr 18, 2023 at 19:54
  • @Walter see godbolt.org/z/76nh7hbTh Commented Apr 18, 2023 at 20:35
  • > that can't be the most efficient way was not the question. The question was > Cleanest way to copy... given an otherwise unspecified constant size array. So this is a perfectly valid answer. It is also much easier to read than std::copy(std::begin(a), std::end(a), b); Commented Feb 15 at 15:18

Not the answer you're looking for? Browse other questions tagged or ask your own question.