18

I am new to C++ and currently learning it with a book by myself. This book seems to say that there are several kinds of arrays depending on how you declare it. I guess the difference between dynamic arrays and static arrays are clear to me. But I do not understand the difference between the STL std::array class and a static array.

An STL std::array variable is declared as:

std::array < int, arraySize > array1;

Whereas a static array variable is declared as:

int array1[arraySize];

Is there a fundamental difference between the two? Or is it just syntax and the two are basically the same?

vsoftco
  • 55,410
  • 12
  • 139
  • 252
Astaboom
  • 317
  • 2
  • 7
  • No difference, just a matter of syntax and I believe that was only available C++ 11 and above However notice that the STL declaration gives you a big toolbox of functions and iterators you can use on your array, as the other one you generally would have to make built in functions yourself to do the trivial things.: Check: http://en.cppreference.com/w/cpp/container/array – Omid CompSCI Nov 23 '16 at 20:07
  • Possible duplicate of [std::array vs array performance](http://stackoverflow.com/questions/30263303/stdarray-vs-array-performance) – coincoin Nov 23 '16 at 20:11
  • 6
    There will be a big difference when you start passing `std::array<>` to functions as opposed to built-in arrays. A `std::array` knows its own size, a built-in array doesn't as it decays to a pointer. – PaulMcKenzie Nov 23 '16 at 20:12
  • 3
    @PaulMcKenzie You can actually pass a C-style array by reference, in which case the size will be known. – vsoftco Nov 23 '16 at 20:14
  • 1
    Off topic minor nag: just call it `std::array`. STL was absorbed into the standard decades ago and `array` came much later. – user4581301 Nov 23 '16 at 20:50

8 Answers8

25

A std::array<> is just a light wrapper around a C-style array, with some additional nice interface member functions (like begin, end etc) and typedefs, roughly defined as

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

One fundamental difference though is that the former can be passed by value, whereas for the latter you only pass a pointer to its first element or you can pass it by reference, but you cannot copy it into the function (except via a std::copy or manually).

A common mistake is to assume that every time you pass a C-style array to a function you lose its size due to the array decaying to a pointer. This is not always true. If you pass it by reference, you can recover its size, as there is no decay in this case:

#include <iostream>

template<typename T, size_t N>
void f(T (&arr)[N]) // the type of arr is T(&)[N], not T*
{
    std::cout << "I'm an array of size " << N;
}

int main()
{
    int arr[10];
    f(arr); // outputs its size, there is no decay happening
}

Live on Coliru

vsoftco
  • 55,410
  • 12
  • 139
  • 252
9

The main difference between these two is an important one.

Besides the nice methods the STL gives you, when passing a std::array to a function, there is no decay. Meaning, when you receive the std::array in the function, it is still a std::array, but when you pass an int[] array to a function, it effectively decays to an int* pointer and the size of the array is lost.

This difference is a major one. Once you lose the array size, the code is now prone to a lot of bugs, as you have to keep track of the array size manually. sizeof() returns the size of a pointer type instead of the number of elements in the array. This forces you to manually keep track of the array size using interfaces like process(int *array, int size). This is an ok solution, but prone to errors.

See the guidelines by Bjarne Stroustroup:

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rp-run-time

That can be avoided with a better data type, which std::array is designed for, among many other STL classes.

As a side note, unless there's a strong reason to use a fixed size array, std::vector may be a better choice as a contiguous memory data structure.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Steve Thibault
  • 304
  • 2
  • 8
7

std::array and C-style arrays are similar:

  • They both store a contiguous sequence of objects
  • They are both aggregate types and can therefore be initialized using aggregate initialization
  • Their size is known at compile time
  • They do not use dynamic memory allocation

An important advantage of std::array is that it can be passed by value and doesn't implicitly decay to a pointer like a C-style array does.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
5

In both cases, the array is created on the stack.

However, the STL's std::array class template offers some advantages over the "raw" C-like array syntax of your second case:

int array1[arraySize];

For example, with std::array you have a typical STL interface, with methods like size (which you can use to query the array's element count), front, back, at, etc.

You can find more details here.

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • 3
    "*In both cases, the array is created on the stack*" - unless it is a member of a struct/class that is allocated on the heap. – Remy Lebeau Nov 23 '16 at 21:08
3

Is there a fundamental difference between the two? or is it just syntax and the two are basically the same?

There's a number of differences for a raw c-style array (built-in array) vs. the std::array.

As you can see from the reference documentation there's a number of operations available that aren't with a raw array:

E.g.: Element access

at()
front()
back()
data()

The underlying data type of the std::array is still a raw array, but garnished with "syntactic sugar" (if that should be your concern).

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
2

The key differences of std::array<> and a C-style array is that the former is a class that wraps around the latter. The class has begin() and end() methods that allow std::array objects to be easily passed in as parameters to STL algorithms that expect iterators (Note that C-style arrays can too via non member std::begin/std::end methods). The first points to the beginning of the array and the second points to one element beyond its end. You see this pattern with other STL containers, such as std::vector, std::map, std::set, etc.

What's also nice about the STL std::array is that it has a size() method that lets you get the element count. To get the element count of a C-style array, you'll have to write sizeof(cArray)/sizeof(cArray[0]), so doesn't stlArray.size() looks much more readable?

You can get full reference here:

http://en.cppreference.com/w/cpp/container/array

Max Raskin
  • 1,042
  • 1
  • 14
  • 26
  • Non-member `begin` and `end` work just fine with C-style arrays. With these other improvements (shift to non-member templates) nothing you say is right: arrays can be handled by algorithms with requiring the wrapper to do so. Arrays have *always* had iterators; making them just like pointers was a founding principle. – JDługosz Nov 24 '16 at 07:05
  • 1
    Added your note about non member begin/end. – Max Raskin Nov 25 '16 at 05:45
  • 2
    «To get the element count of a C-style array, you'll have to write » yuck, and no you don’t. The template shown in vsoftco’s answer illustrates how N is deduced as a template argument. Or just use `end(a)-begin(a)` but why do you need to do that when you *should* be passing the iterators or a “range”. A C array **is** a perfectly good range: the wrapper of array is not needed for any of these reasons. – JDługosz Nov 25 '16 at 06:41
1

Usually you should prefer std::array<T, size> array1; over T array2[size];, althoug the underlying structure is identical.

The main reason for that is that std::array always knows its size. You can call its size() method to get the size. Whereas when you use a C-style array (i.e. what you called "built-in array") you always have to pass the size around to functions that work with that array. If you get that wrong somehow, you could cause buffer overflows and the function tries to read from/write to memory that does not belong to the array anymore. This cannot happen with std::array, because the size is always clear.

Striezel
  • 3,693
  • 7
  • 23
  • 37
  • In C++ there is no need to always pass the size around, even for C-style arrays. You can pass the array by reference via a template function and recover its size. – vsoftco Nov 23 '16 at 20:29
1

IMO,

  • Pros: It’s efficient, in that it doesn’t use any more memory than built-in fixed arrays.

  • Cons: std::array over a built-in fixed array is a slightly more awkward syntax, and that you have to explicitly specify the array length (the compiler won’t calculate it for you from the initializer).