145

If I want to build a very simple array like:

int myArray[3] = {1,2,3};

Should I use std::array instead?

std::array<int, 3> a = {{1, 2, 3}};

What are the advantages of using std::array over usual ones? Is it more performant? Just easier to handle for copy/access?

Arcyno
  • 4,153
  • 3
  • 34
  • 52
  • 3
    defining multi dimensional array with std:: will be difficult – goGud May 15 '15 at 15:33
  • 30
    @goGud: Not difficult, just more verbose. – Mike Seymour May 15 '15 at 15:34
  • 1
    Pointer decay, taking a reference etc..., many things are strange about c-arrays. The iterator may be a pointer in case of c-arrays and `for (auto i = ++std::begin(myArray); . . . ` may not even compile (it seems that temporaries of fundamental type are not mutable, at least not with clang 6) – Patrick Fromberg May 13 '18 at 17:14
  • Initialization also differs magically: ``struct Direction { int32_t dw; int32_t dh; };`` and ``static const Direction DIRECTIONS[DIRECTIONS_COUNT] { { -1, 1}, {0,1}, {1,1} , { 1, 0 }, {1,-1}, {0,-1} , {-1,-1}, {-1,0} };`` compiles. But if you change to a ``std::array`` with same initializer list, suddenly you get "too many initializers" error. (VS 2019 Community with language = C++17) – BitTickler Oct 08 '19 at 21:58
  • Why the double brackets in the `std::array` initialization? – Marc.2377 Dec 08 '19 at 21:36
  • 1
    @Marc.2377 `std::array` is just a wrapper for C-style arrays. If I'm not mistaking, in some earlier versions of C++ you couldn't initialize it with single brackets. However, don't take my word for it, since I haven't used them much – H-005 Jul 20 '20 at 09:57

7 Answers7

164

What are the advantages of using std::array over usual ones?

It has friendly value semantics, so that it can be passed to or returned from functions by value. Its interface makes it more convenient to find the size, and use with STL-style iterator-based algorithms.

Is it more performant ?

It should be exactly the same. By definition, it's a simple aggregate containing an array as its only member.

Just easier to handle for copy/access ?

Yes.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
62

A std::array is a very thin wrapper around a C-style array, basically defined as

template<typename T, size_t N>
struct array
{
    T _data[N];
    T& operator[](size_t);
    const T& operator[](size_t) const;
    // other member functions and typedefs
};

It is an aggregate, and it allows you to use it almost like a fundamental type (i.e. you can pass-by-value, assign etc, whereas a standard C array cannot be assigned or copied directly to another array). You should take a look at some standard implementation (jump to definition from your favourite IDE or directly open <array>), it is a piece of the C++ standard library that is quite easy to read and understand.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • 1
    Minor correction, it's defined as a struct in the docs: https://en.cppreference.com/w/cpp/container/array – Overt_Agent Jul 26 '21 at 09:23
  • 3
    @Overt_Agent Thanks, corrected (although the `class...{public:...}` had the same access rules as a struct ;) – vsoftco Jul 26 '21 at 19:37
36

std::array is designed as zero-overhead wrapper for C arrays that gives it the "normal" value like semantics of the other C++ containers.

You should not notice any difference in runtime performance while you still get to enjoy the extra features.

Using std::array instead of int[] style arrays is a good idea if you have C++11 or boost at hand.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
24

Is it more performant ?

It should be exactly the same. By definition, it's a simple aggregate containing an array as its only member.

The situation seems to be more complicated, as std::array does not always produce identical assembly code compared to C-array depending on the specific platform.

I tested this specific situation on godbolt:

#include <array>
void test(double* const C, const double* const A,
          const double* const B, const size_t size) {
  for (size_t i = 0; i < size; i++) {
    //double arr[2] = {0.e0};//
    std::array<double, 2> arr = {0.e0};//different to double arr[2] for some compiler
    for (size_t j = 0; j < size; j++) {
      arr[0] += A[i] * B[j];
      arr[1] += A[j] * B[i];
    }
    C[i] += arr[0];
    C[i] += arr[1];
  }
}

GCC and Clang produce identical assembly code for both the C-array version and the std::array version.

MSVC and ICPC, however, produce different assembly code for each array version. (I tested ICPC19 with -Ofast and -Os; MSVC -Ox and -Os)

I have no idea, why this is the case (I would indeed expect exactly identical behavior of std::array and c-array). Maybe there are different optimization strategies employed.

As a little extra: There seems to be a bug in ICPC with

#pragma simd 

for vectorization when using the c-array in some situations (the c-array code produces a wrong output; the std::array version works fine).

Unfortunately, I do not have a minimal working example for that yet, since I discovered that problem while optimizing a quite complicated piece of code.

I will file a bug-report to intel when I am sure that I did not just misunderstood something about C-array/std::array and #pragma simd.

Community
  • 1
  • 1
Henryk
  • 261
  • 3
  • 2
13

std::array has value semantics while raw arrays do not. This means you can copy std::array and treat it like a primitive value. You can receive them by value or reference as function arguments and you can return them by value.

If you never copy a std::array, then there is no performance difference than a raw array. If you do need to make copies then std::array will do the right thing and should still give equal performance.

b4hand
  • 9,550
  • 4
  • 44
  • 49
3

You will get the same perfomance results using std::array and c array If you run these code:

std::array<QPair<int, int>, 9> *m_array=new std::array<QPair<int, int>, 9>();
    QPair<int, int> *carr=new QPair<int, int>[10];
    QElapsedTimer timer;
    timer.start();
    for (int j=0; j<1000000000; j++)
    {

        for (int i=0; i<9; i++)
        {
            m_array->operator[](i).first=i+j;
            m_array->operator[](i).second=j-i;
        }
    }
    qDebug() << "std::array<QPair<int, int>" << timer.elapsed() << "milliseconds";
    timer.start();
    for (int j=0; j<1000000000; j++)
    {

        for (int i=0; i<9; i++)
        {
            carr[i].first=i+j;
            carr[i].second=j-i;
        }
    }
    qDebug() << "QPair<int, int> took" << timer.elapsed() << "milliseconds";
    return 0;

You will get these results:

std::array<QPair<int, int> 5670 milliseconds
QPair<int, int> took 5638 milliseconds

Mike Seymour is right, if you can use std::array you should use it.

2

While std::array has some advantages, as outlined in the other helpful answers, some have stated things like, "… there is no performance difference than a raw array."

This simply is not true and is misleading to anyone working in true embedded development (time critical, bare metal).

Quick and dirty test using an STM32G0B1 running at 50MHz (CPU): Writing to a std::array takes approximately 5 µS longer than to a raw C style array. To me, this is a significant performance difference that cannot be ignored.

Todd
  • 21
  • 4
  • care to post your benchmark? – Matt Spicer May 16 '23 at 15:56
  • @MattSpicer It was just a quick test. Easy enough to do and not worth keeping. A simple set/clear of a test pin to give a pulse to scope and measure time it takes to write to one type of array vs another. – Todd May 18 '23 at 10:31