0

In C++, would it be better (performance-wise) to iterate through elements in an array or vector using the array.at(i) function or by using array[i]? Is one more efficient than the other?

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
ethane
  • 2,329
  • 3
  • 22
  • 33

3 Answers3

7

The at() method performs bounds checking on the passed index, operator[] doesn't.

So using at() may be slower from a performance perspective if you have lots of element accesses.

(I recall I did some tests with big matrices in an older version of MSVC, and there was a difference between accessing each item with and without bounds checking. As usual, when in doubt, measure.)

Note also that in some implementations like MSVC's one, operator[] performs bounds checking in debug builds.

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • 1
    Regarding your last sentence: More precisely, it's either the `/MDd` or the `/MTd` compiler flag which enables the checks. – Christian Hackl Mar 01 '16 at 12:00
  • 1
    More accurately, `operator[]` doesn't *have* to perform bounds checking. So it is implementation dependent whether it does or not. Typically, optimized builds do not, unoptimized builds often do. – Martin Bonner supports Monica Mar 01 '16 at 12:57
  • @Martin Is that true? I’ve never heard of an optimiser that chooses different code paths. *Debug* builds often include checks, true. But how do you even test for the presence of an optimiser in code? – Konrad Rudolph Mar 01 '16 at 13:54
  • @KonradRudolph: In my mind, "an optimized build" is not quite the same as "an optimizer". An optimized build is likely to run the optimizer, but it will probably also set #define flags to disable time-consuming checks. – Martin Bonner supports Monica Mar 01 '16 at 13:56
  • 1
    @Martin Alright, but what does this mean in the context of `std::vector::operator[]` then? What are these flags? Or are you talking about debug builds? – Konrad Rudolph Mar 01 '16 at 14:09
  • @KonradRudolph: I can imagine a bounds check that's labelled `Unreachable` using an implementation `pragma`. The optimizer, seeing that label, would remove the branch, whereas the debug build would simply execute it as written. This would be easier than a whole bunch of `#ifdef`'s. – MSalters Mar 01 '16 at 14:49
5

For std::vector::at or std::array::at,

Returns a reference to the element at specified location pos, with bounds checking.

And for std::vector::operator[] or std::array::operator[],

Returns a reference to the element at specified location pos. No bounds checking is performed.

So in theory, operator[] would be more efficient. In the actual situation, you might measure.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
0

If the code is truly iterating through the array, then the iteration code is responsible for ensuring that accesses are not out of bounds. For example:

for (int i = 0; i < my_vec.size(); ++i)
    std::cout << my_vec[i] << '\n';

There's no need to build in extra overhead by checking whether i is out of bounds. It won't be.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165