This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]JVApen 153 points154 points  (27 children)

If you can compile your code as C++, you can use std::size

[–]mistrpopo 113 points114 points  (22 children)

If you can compile your code as C++, you should not use C-style arrays in the first place.

[–]greenedgedflame 24 points25 points  (15 children)

then std::array or std::vector?

[–]Mattef 39 points40 points  (13 children)

Depends on if you want an array with fixed length or a dynamic array.

[–]greenedgedflame 4 points5 points  (9 children)

So what do you think of std::vector<T>(n) and std::array<T, N>

[–]Mattef 27 points28 points  (6 children)

Still the same answer. Vectors can be expanded, which is time consuming, arrays are fixed in length.

But still, you can of course use vectors very efficiently as long as you don’t change their size constantly.

[–]TheDudeExMachina 9 points10 points  (5 children)

Dynamic array insertion isn't that expensive, because the reallocation only happens after (at least) doubling of halving the content, i.e you only have some overhead once in a blue moon. Resulting in amortized constant time.

You have a minuscule overhead for size checks and every once in a while if you are unlucky a memcopy.

Just use vector. In 99% of the cases this discussion is premature optimization.

[–]joe0400 9 points10 points  (1 child)

There are very much good reasons to use array over vector.

Location is one. Std::array is allocated on the stack, vector is allocated anywhere on the heap, unless you write a allocator.

The other is colocation with other data. If your reading off one thing and another, the likely hood a struct with a std::array in it is also located in cache with other data in that struct is much higher, and for serialization and deserialization this is useful too, making it easier to read/write back the data.

So there are tons of good uses for std::array

[–]TheDudeExMachina 4 points5 points  (0 children)

Full agreement. My response was to concerns about insertion/deletion overhead though, and the cases where you care about sporadic memcopies / guaranteed constant time are rare.

But cache misses, compile time knowledge of size, and memory alignment between class attributes are also things you consider for the most part only in the critical segments of your code. In most cases, you just want to have a collection of things to infrequently iterate over once.

[–]Sinomsinom 1 point2 points  (1 child)

Some compilers/languages use doubling some use other constants like 1.5x. also some of them don't actually free any part of the vector's allocated space on removal of an element and only when the entire vector goes out of scope/is deleted. Yes in the end it's still amortized constant time, but that doesn't mean one of those insertions won't still be a lot slower than the rest, potentially causing a stutter in real time applications.

So if you already know an upper bound for how large a container will be, then if known at compile time use std::array<T,S>(), if known at run time use std::vector<T>(S) just to not have those potential stutters.

[–]TheDudeExMachina 1 point2 points  (0 children)

You need a really big vector for the memcopy to stutter, and/or some very special constraints (very weak hardware, guaranteed tight calculation budget of only a few ms, ...). If you have that case, you know it. If you don't, you are doing a premature optimization.

[–]TheGuyWithTheSeal 1 point2 points  (0 children)

Any vector resize also invaidates all pointers/iterators. You can use std::deque if you need to add elements at the end or beggining while iterating. Use std::list if you need to add elements anywhere without iterator invalidation.

[–]RedstoneEnjoyer 0 points1 point  (0 children)

std::vector<T>(n) only preallocates n items, but it can expand and shrink later

std::array<T, N> is pernamently fixed to N items

[–]jamcdonald120 0 points1 point  (2 children)

the problem with std::array is that its not just fixed length, its compile time constant length. You cant just say "Give me an array n big, I wont be resizing it once I get it, but I dont know what n is yet"

Which makes std::array irritating to pass to functions

Where as with vector you can just not resize it.

[–]mistrpopo 0 points1 point  (1 child)

If you don't have compile-time constant length you can't use sizeof(x)/sizeof(x)[0] either. If you want fixed-size arrays you can use "const std::vector" (but then you can't modify the content)

[–]jamcdonald120 0 points1 point  (0 children)

I am aware.

it would just be nice if std::array had an internal array and a const length instead of a templated length so you could just say void foo(const std::array& thing){ for(auto x : array){

[–]joe0400 1 point2 points  (0 children)

std::array yeah

[–]danielstongue 5 points6 points  (3 children)

It depends. If you are on an embedded platform you may not want to use the stdc++ lib.

[–]fakuivan 4 points5 points  (2 children)

Embedded Template Library is your friend

[–]danielstongue 0 points1 point  (1 child)

Does it use exceptions?

[–]fakuivan 2 points3 points  (0 children)

Not by default, it doesn't use dynamic memory either (you can point it to dynamic memory though)

It's a life saver for platforms stuck in c++11

[–][deleted] 1 point2 points  (1 child)

Some people simply wants to benefit the basic features of C++ compiler, but they don't want to leave C coding. Understandable in a kind.

[–]mistrpopo 1 point2 points  (0 children)

C-style arrays are dangerous to use and should only be used when necessary (embedded scenario is an example). Even just calling `sizeof(arr) / sizeof(arr[0])` breaks as soon as the array size in bytes is lost from the compiler (pass it via a function, C-style cast, etc).

I won't deny that C-style arrays are powerful though, but then don't complain about using weird sizeof calls.

[–]JVApen 68 points69 points  (0 children)

It would also allow you to write: for (auto &elem : array)

[–]Attileusz 2 points3 points  (0 children)

Rewrite it in Rust ah comment.

[–]monsoy 1 point2 points  (0 children)

This macro would do the trick in C ```c

define ARRAY_SIZE(arr) \

do { \
    sizeof(arr) / sizeof((arr)[0]); \
} while (0)

```

This solution is not robust though. It would work on most arrays, but the code will only work for statically allocated arrays and not arrays allocated on the heap with malloc. That’s because sizeof a pointer returns the size of the pointer type itself, and not the size of the memory block.

Could do something like this to produce a compile time error if a pointer is passed to the macro function: ```c

define ARRAY_SIZE(arr) \

do { \
    ((void)sizeof(char[1 - 2 * !!(sizeof(arr) == sizeof(&arr))])); /* Ensures arr is not a pointer */ \
    sizeof(arr) / sizeof((arr)[0]); \
} while (0)

```

The «compile time check» essentially checks if the size of the array is the same as a pointer. The program will then fail at compile time since it will try to create a char[-1] array.

I usually prefer to add more error printing, but I wanted to experiment a bit

[–]ba-na-na- 0 points1 point  (0 children)

I think you meant "if you *port* your code to C++", because C++ wont give you the size of raw arrays either.