I'm just getting into C++ and I think I have a handle on pointers, but std::accumulate()
has me confused.
Given the array:
int a[3] = { 5, 6, 7 };
I'd like to sum the values of the array with std::accumulate()
, so I pass it a pointer to the first element, then the last, then the starting value of the accumulator.
std::accumulate(a, a + 2, 0);
std::accumulate(&a[0], &a[2], 0);
Oops: either of these returns the sum of only the first two elements: 11
.
On the other hand, if the second argument is a nonsensical pointer, just out of bounds...
std::accumulate(a, a + 3, 0);
std::accumulate(&a[0], &a[3], 0);
... the correct value of 18
is returned.
Could someone please explain this? I realise that I could avoid using simple arrays, but that's beside the point.
std::accumulate() is a built-in function in C++'s Standard Template Library. The function takes in a beginning iterator, an ending iterator, initial value, and (by default) computes the sum of the given initial value and the elements in the given range. The function can also be used for left folding.
As I expect, the manually unrolled loop is the fastest one, but more interesting is that std::accumulate is much slower than simple loop.
The std::array is designed as zero-overhead wrapper for c-style arrays. It will provide a value like semantics equally to the other C++ containers. A std::array should have same runtime performance as a c-style array.
std::array is just a class version of the classic C array. That means its size is fixed at compile time and it will be allocated as a single chunk (e.g. taking space on the stack). The advantage it has is slightly better performance because there is no indirection between the object and the arrayed data.
C++ ranges are defined as [first, last)
, and all the STL algorithm work like that. In this case, std::accumulate
sums up all the elements behind the iterator-defined range, starting with first
and ending at last
without actually dereferencing it.
Thus, calling it like std::accumulate(a, a+3, 0)
is actually correct and equal to calling it with std::accumulate(begin(a), end(a), 0)
.
Also note that this doesn't fall foul of the "no pointers to outside of allocated arrays" rule, as there is a specific exception for pointer to just behind the last element.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With