98

Since std::list and std::vector exist, is there a reason to use traditional C arrays in C++, or should they be avoided, just like malloc?

Paul Renton
  • 2,652
  • 6
  • 25
  • 38
Andreas
  • 7,470
  • 10
  • 51
  • 73
  • 1
    possible duplicate of [What is the difference between std::array and std::vector? When do you use one over other?](http://stackoverflow.com/questions/6632971/what-is-the-difference-between-stdarray-and-stdvector-when-do-you-use-one-o) – Alok Save May 23 '12 at 10:31
  • 19
    @Als: That question concerns the difference between two specific containers, while this question concerns the difference between raw arrays and standard containers in general. – Jon Purdy May 23 '12 at 16:58

11 Answers11

109

In C++11 where std::array is available, the answer is "yes, arrays should be avoided". Prior to C++11, you may need to use C arrays to allocate arrays in the automatic storage (i.e. on the stack).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 3
    many compilers do still lack C++11 support however. You will have to decide when it's better to use one rather than the other given the lack of std::array – Nowayz May 25 '12 at 09:59
  • 4
    std::array is a template, which impacts large projects in terms of build time and possibly code size since for each combination of T,N the template is instantiated anew. – zvrba Jun 10 '12 at 08:37
  • std::vector guarantees data alignment by standard, so it can be used almost everywhere. With C++11 there really is no reason to use C arrays. – Nils Jun 10 '12 at 08:54
  • 16
    @Nils arrays guarantee alignment too. Plus, automatic storage allocation ("the stack") is way faster than dynamic storage allocation. If I *know* I have *exactly* 3 elements [e.g., coordinates of a triangle], there's no reason to use vector. – zvrba Jun 10 '12 at 09:15
  • Ah yes, if it has to live on the stack, then you cannot use vector IIRC. – Nils Jun 10 '12 at 10:22
  • 10
    @zvrba - Check the generated assembly when using std::array vs C arrays. No difference at all. – Nemanja Trifunovic Jun 10 '12 at 13:54
  • While theoretically better in every way, in practice `std::array` is a headache to use. – Swiss Jun 12 '12 at 08:42
  • There's also boost::array that can be used if std::array is not available. – Macke Jun 17 '12 at 20:37
  • But on the other hand, C array could be aligned through compile support, how can std::array do it? – superK Aug 05 '13 at 01:52
85

Definitely, although with std::array in C++11, practically only for static data. C style arrays have three important advantages over std::vector:

  • They don't require dynamic allocation. For this reason, C style arrays are to be preferred where you're likely to have a lot of very small arrays. Say something like an n-dimension point:

    template <typename T, int dims>
    class Point
    {
        T myData[dims];
    // ...
    };
    

    Typically, one might imagine a that dims will be very small (2 or 3), T a built-in type (double), and that you might end up with std::vector<Point> with millions of elements. You definitely don't want millions of dynamic allocations of 3 double.

  • The support static initialization. This is only an issue for static data, where something like:

    struct Data { int i; char const* s; };
    Data const ourData[] =
    {
        { 1, "one" },
        { 2, "two" },
        //  ...
    };
    

    This is often preferable to using a vector (and std::string), since it avoids all order of initialization issues; the data is pre-loaded, before any actual code can be executed.

  • Finally, related to the above, the compiler can calculate the actual size of the array from the initializers. You don't have to count them.

If you have access to C++11, std::array solves the first two issues, and should definitely be used in preference to C style arrays in the first case. It doesn't address the third, however, and having the compiler dimension the array according to the number of initializers is still a valid reason to prefer C style arrays.

svick
  • 236,525
  • 50
  • 385
  • 514
James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 11
    C-style array initialization also removes the need to repeat yourself. `int i[] = { 1, 2, 3 };` continues working with `int i[] = { 1, 2, 3, 4 };`. `array` needs to be manually changed to `array`. –  May 23 '12 at 12:51
  • 10
    @JoeWreschnig A change which you can easily forget. If you add an element, the compiler should complain, but if you remove one, you'll end up with an extra, 0 initialized element at the end. I still use C style arrays extensively for this sort of static data. – James Kanze May 23 '12 at 12:56
  • 4
    The first sentence doesn’t make sense. – Konrad Rudolph May 23 '12 at 14:37
  • 4
    The third point can be solved rather elegantly by using a [`make_array` function](https://gist.github.com/2775736), similar to `make_pair` etc. Hat-tip to [@R. Martinho Fernandes](http://chat.stackoverflow.com/transcript/message/3820452#3820452). – Konrad Rudolph May 23 '12 at 15:03
  • @KonradRudolph: Sure it does. Andreas asks “Should arrays be used in C++?”, to which James replies “Definitely, although with `std::array` in C++11, [they should be used] practically only for static data”. – Jon Purdy May 23 '12 at 17:02
  • @Jon I still don’t see it. *Without* `std::array` *before* C++11, they should practically only be used for static data. *With* `std::array` even that use-case isn’t as strong any more. – Konrad Rudolph May 23 '12 at 18:26
  • @KonradRudolph: Fair enough. I was just interpreting what’s written. – Jon Purdy May 23 '12 at 18:30
  • @KonradRudolph Is `make_array` a const expression. Or does it cause dynamic initialization? – James Kanze May 24 '12 at 08:55
  • @James Well you *can* make it a `constexpr`. In fact, let me amend the gist … there you go (and yes, I tested it, this works). – Konrad Rudolph May 24 '12 at 09:16
  • With clang I had to put `constexpr` after the arrow. Not sure if that's just a compiler artifact though. Edit: Only in clang 2.9. In 3.1 it has to go next to auto – Per Johansson Jun 10 '12 at 16:07
15

Never say "never", but I'd agree that their role is greatly diminished by true data structures from STL.

I'd also say that encapsulation inside objects should minimize the impact of choices like this. If the array is a private data member, you can swap it in or out without affecting clients of your class.

duffymo
  • 305,152
  • 44
  • 369
  • 561
11

I have worked on safety critical systems where you are unable to use dynamic memory allocation. The memory has to always be on the stack. Therefore in this case you would use arrays as the size is fixed at compile time.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • 8
    Before C++11 i would have agreed, but `std::array` allocates on the stacks and basically has no overhead on a raw array. – 111111 May 23 '12 at 10:46
  • 5
    @111111 - Agreed. But I know of some folks in that industry has not moved to C++11 yet – Ed Heal May 23 '12 at 10:53
  • I know that is why I didn't downvote you, but I think boost had a version and it is easy to roll your own as well. – 111111 May 23 '12 at 10:56
  • 6
    but in safety critical systems, you don't use new compiler features (less tested), and you don't use boost. – James Kanze May 23 '12 at 11:35
  • 3
    Many safety critical systems are built on OLD compilers that don't even have the newer compiler features because changing toolchains is a slow, expensive process that requires tons of paperwork, testing, and certifications. – Brian McFarland Jun 10 '12 at 12:17
  • `std::array` requires C++11, and `boost::array` requires Boost, but `template< typename T, std::size_t N > struct array { T arr[ N ]; typedef T arr_t[N]; operator arr_t &(){ return arr; } operator arr_t const &() const { return arr; } };` is a lot of future proofing in just 7 lines. – Potatoswatter Jul 06 '12 at 19:32
  • I am flattered that you looked up my past posts. But using templates muddies the waters sometimes if not careful. – Ed Heal Jul 06 '12 at 19:45
6

array in c++ gives you fixed size fast alternative of dynamic sized std::vector and std::list. std::array is one of the additions in c++11. It provides the benefit of std containers while still providing the aggregate type semantics of C-style arrays.

So in c++11 i'd certainly use std::array, where it is required, over vector. But i'd avoid C style array in C++03.

Vikas
  • 8,790
  • 4
  • 38
  • 48
4

Most usually, no, I can't think of a reason to use raw arrays over, say, vectors. If the code is new.

You might have to resort to using arrays if your libraries need to be compatible with code that expects arrays and raw pointers.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    ... but since C++03 a vector "actually has" an array, which you can access by pointer to read or write. So that covers most cases of code that expects pointers to arrays. It's only really when that code allocates or frees the array that you can't use a vector. – Steve Jessop May 23 '12 at 10:31
  • @SteveJessop can you access the internal array? – Luchian Grigore May 23 '12 at 10:37
  • 1
    @LuchianGrigore: `vector.data()` in C++11 or `&vector.front()` previously. – Mike Seymour May 23 '12 at 10:40
  • @Luchian: provided the vector isn't empty, you can take a pointer to an element (and if it is empty, you can pass a null pointer and a length of 0 to any sensibly-written function that accepts the edge case of a zero-sized buffer). Pretty much the sole purpose of the vector contiguity guarantee added in C++03 was to allow vectors to be used as buffers by pointer-oriented code. – Steve Jessop May 23 '12 at 10:46
  • 1
    @SteveJessop And the fact that a lot of people thought it was guaranteed anyway, and it was considered preferable to not disappoint them. – James Kanze May 23 '12 at 11:34
4

I know a lot of people are pointing out std::array for allocating arrays on the stack, and std::vector for the heap. But neither seem to support non-native alignment. If you're doing any kind of numeric code that you want use SSE or VPX instructions on (thus requiring 128 or 256 byte alignment respectively), C arrays would still seem to be your best bet.

gct
  • 14,100
  • 15
  • 68
  • 107
3

I would say arrays are still useful, if you are storing a small static amount of data why not.

james82345
  • 530
  • 4
  • 13
2

The only advantage of an array (of course wrapped in something that will manage automatically its deallocation when need) over std::vector I can think about is that vector cannot pass ownership of its data, unless your compiler supports C++11 and move constructors.

Tadeusz Kopec for Ukraine
  • 12,283
  • 6
  • 56
  • 83
2

C style arrays are a fundamental data structure, so there will be cases when it is better to use it. For the general case, however, use the more advanced data structures that round off the corners of the underlying data. C++ allows you to do some very interesting and useful things with memory, many of which work with simple arrays.

James Wynn
  • 686
  • 6
  • 6
  • 3
    How are C-style arrays more fundamental than `std::array`s? Both will in many cases be compiled to the same assembly. – leftaroundabout May 23 '12 at 12:35
  • 1
    More fundamental in that it is more basic. You know what an array is going to do, std::array may have implementation quirks since it relies on the standard library. – James Wynn May 23 '12 at 14:43
  • 1
    @JamesWynn Not really. `std::array` has precisely defined semantics built on top of static arrays. – Konrad Rudolph May 23 '12 at 20:26
1

You should use STL containers internally, but you should not pass pointers to such containers between different modules, or you will end up in dependency hell. Example:

std::string foo;
//  fill foo with stuff
myExternalOutputProc(foo.c_str());

is a very good solution but not

std::string foo;
//  fill foo with stuff
myExternalOutputProc(&foo);

The reason is that std::string can be implemented in many different ways but a c-style string is always a c-style string.

user877329
  • 6,717
  • 8
  • 46
  • 88
  • I think what you are trying to say is: Don't link different object code together if different compilers / implementations of the standard library were used to create them. That's certainly true. How does this relate to the original question? – jogojapan Jan 23 '13 at 09:54
  • It is just an advice *when* to use arrays or STL containers. Build data using a container, pass it as an array. For other data that strings you would have something like myExternalOutputProc(foo.rawPointerGet(),foo.count()); – user877329 Jan 23 '13 at 11:13
  • But these problems only arise when you combine different implementations of the standard library in the same project. That's crazy. In any normal piece of code, it is perfectly ok to pass, say, a vector, by reference (or, in C++11, move it) to a function. – jogojapan Jan 24 '13 at 00:35
  • 1
    I just happen to like plug-ins – user877329 Jan 24 '13 at 13:01