For traversing a C array using STL functions, the std::begin
and std::end
functions are quite handy equivalents of .begin()
and .end()
. However, there are no std::rbegin
and std::rend
equivalents of the reverse iterators for bidirectional C++ containers. Does such an equivalent exist under some other name, or is one easily made? I realize one difficulty is that std::begin
generally returns a raw pointer, and for the reverse case this would need a wrapper so that the ++ operation could be overloaded. A very incomplete implementation might look like
template<class T>
class ReverseArrayIterator {
public:
ReverseArrayIterator(T* ptr) : _ptr(ptr) {}
operator T*() {
return _ptr;
}
void operator++() {
--_ptr;
}
T operator*() {
return *_ptr;
}
bool operator!= (ReverseArrayIterator& rhs) {
return _ptr != rhs._ptr;
}
private:
T* _ptr;
};
template<class T, size_t size>
ReverseArrayIterator<T> rbegin(T (&array)[size]) {
return ReverseArrayIterator<T>(&array[0] + size - 1);
}
template<class T, size_t size>
ReverseArrayIterator<T> rend(T (&array)[size]) {
return ReverseArrayIterator<T>(&array[0] - 1);
}
I tested this bare-bones implementation with the following code:
int x[] = {1,2,3,4,5,6,0,0,0,10,11,12};
auto a = std::find(std::begin(x),std::end(x),0);
auto b = std::find(rbegin(x),rend(x),0);
cout << std::distance(x,a) << endl;
cout << std::distance(x,(int*)b) << endl;
Could this be fleshed out into a fully operational reverse-iterator class for C arrays, or will I run into further obstacles down the road? One possible roadblock seems to be implicit conversion to raw pointers, which I'd hoped would be used in functions like std::distance -- the above snippet won't compile with std::distance(x,b)
(or similar functions, presumably) but needs the manual (int*)
cast.
The reverse iterator adaptor iterates through the adapted iterator range in the opposite direction.
The C++ function std::vector::rbegin() returns a reverse iterator which points to the last element of the vector. Reverse iterator iterates reverse order that is why incrementing them moves towards beginning of vector.
They use iterators. An iterator is an object designed to traverse through a container (e.g. the values in an array, or the characters in a string), providing access to each element along the way.
The rbegin() is a function in C++ STL. It returns a reverse iterator which points to the last element of the map. The reverse iterator iterates in reverse order and incrementing it means moving towards beginning of map.
(I'm turning the comments into an answer to help others. Credits to chris and StoryTeller.)
Since C++14 there are rbegin() and rend() just like you describe.
There is also an adapter class to convert a (forward) iterator into a reverse iterator. Please note the forward begin()
iterator should be passed to make_reverse_iterator
to make the reverse iterator, and vice versa:
std::vector<int> v{ 1, 3, 10, 8, 22 };
std::copy(
std::make_reverse_iterator(v.end()),
std::make_reverse_iterator(v.begin()),
std::ostream_iterator<int>(std::cout, ", "));
Use a span to wrap your array, and don't bother with hand-rolling the kind of code you suggest.
Spans are lightweight wrappers for contiguous sequences of values in memory, providing you with all the "amenities" of a standard library container over those values - including reverse iterators, ranged for loops and so on.
Spans have entered the standard in C++20, but you asked about C++11, so you can use the C++ guidelines support library's span, e.g. from the GSL-lite implementation, that supports C++11 (Microsoft's GSL doesn't).
Spans are reference-types and are extremely lightweight - and very often just get optimized away. So using a span often won't cost you anything.
In your example, with a span, you can rewrite the code as follows:
#include <iterator>
#include <gsl/gsl-lite.hpp>
#include <iostream>
int main()
{
int raw_x[] = {1, 2, 3, 4, 5, 6, 0, 0, 0, 10, 11, 12};
auto x = gsl::span<int>{raw_x};
auto a = std::find(x.begin(), x.end(),0);
auto b = std::find(x.rbegin(), x.rend(),0);
std::cout << std::distance(x.begin(), a) << std::endl;
std::cout << std::distance(x.rend(), b) << std::endl;
}
and this compiles (GodBolt).
Note I used the rbegin()
and rend()
members rather than std::rbegin()
and std::rend()
since the latter are not yet standardized in C++11.
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