In C++, using iterators on containers is the way to go, rather that doing pointer arithmetic as shown in you code sample.
Iterators are also preferable to raw indexes, because it makes your code compatible with any container (for instance a set or a map don't have indexes).
With a recent STL, the toolkit available to manipulate iterators has become quite versatile:
std::prev(iterator, n)
moves an iterator n ranks backwards (towards the beginning of the collection) (ref)
std::next(iterator, n)
moves forward (ref)
std::distance(a, b)
computes the number of elements between to iterators, it is very useful for checking that you're not out of bounds (ref)
Using iterators will also have another nice side-effect: you will be able to use one of the many algorithms already available in the standard library, for example from <algorithm>
or <numeric>
.
It turns out there IS a function that already computes the sum of a range of elements : std::accumulate
. All you need to do is to use it according to your needs (ref. on accumulate).
Here is the beginning of an implementation that is not perfect but that should do OK most of the time.
#include <functional>
#include <numeric>
int sum(const std::vector<int>& v,
const std::vector<int>::const_iterator elem,
size_t radius)
{
auto first_radius = (std::abs(std::distance(std::cbegin(v), elem)) < radius)
? std::cbegin(v)
: std::prev(elem, radius);
auto last_radius = (std::abs(std::distance(elem, std::cend(v))) < radius)
? std::cend(v)
: std::prev(elem, radius);
return std::accumulate(first_radius, last_radius, 0, std::plus<int>());
}
It could seem a bit overwhelming if you are not used to the syntax, but most of this is bound checking. first_radius
and last_radius
are iterators to the bounds of you "mask" radius, making sure that they are not "outside" of the vector (note that I'm not sure this code is 100% bug-free). Afterwards, just let std::accumulate
do the heavy lifting for us!
You can use this code like that:
std::vector<int> x = { 0, 1, 0, 1, 0, 1};
const int a = sum(x, std::next(std::cbegin(x), 3), 15);
const int b = sum(x, std::prev(std::cend(x), 1), 2);
Depending on how familiar you are with the language, it can be a lot of information. It is worth taking some time to look up the documentation for the function I used here, since it is really the idiomatic way to do it (for C++, mind you).
As a closing note : you must have noticed I worked on a std::vector
in my example. Well, nice thing with iterators: we could make this function completely container agnostic!
Using templates, it could work for maps, arrays, sets, your custom container... you name it. But this should be enough for this time... Don't mind asking me about that template trick if you're interested.
Have fun!