C++ reverse_iterator Alternatives - c++

I am attempting to write a two-pass algorithm incorporating some legacy code. I want to move through a particular container twice, once in order and once in reverse order. Obviously, my first thought was to use an iterator and a reverse_iterator, but strangely the designers of the container class I'm using did not see fit to define a working reverse_iterator for the container (reverse_iterators here cannot be dereferenced like iterators can be). I already have an algorithm that requires a reverse_iterator.
My thought is to use the first pass iterator for the first part of the algorithm, and as I perform the algorithm push_front the items into a new container, then iterate through the new container. This will take up memory, which isn't critical in my application, but made me wonder: are there any cleaner alternatives to reverse_iterators in C++, or should I take the time to rework my algorithm using only forward iterators?

If you need to iterate over the elements of a container in reverse order, you don't necessarily need to use a reverse iterator.
If the container has bidirectional iterators, then you can use ordinary iterators and use --it to iterate from end() to begin() instead of using ++it to iterate from begin() to end().
Since this is a bit tricky, you can use the std::reverse_iterator wrapper to convert an ordinary iterator into a reverse iterator (this basically swaps ++ and -- and encapsulates the trickery required to get this to work).
If the container doesn't have bidirectional iterators then that means it's impossible to iterate over the elements of the container in reverse order, in which case you would need either to rewrite your algorithm or to use a different container.
Any container that has bidirectional iterators, it should provide reverse iterator functionality; this is part of the STL and C++ Standard Library "Container" concept.

Related

Retrieving data from vectors and unordered_sets

I've started to put data into vectors and unordered_sets. I've worked out fairly easily how to put the data in, and I know how to get the data out if I need to unload all the data, for example:
for (auto i : vehicles)
MakeSpawnInfoVehicle(i.AddedInformation);
However, I've reached a point where I want just one element of information from either the unordered_sets or vectors such as what ever the 10th entry is in the vector or the unordered_set.
If someone could provide a basic example of both, I'm sure I'll understand it.
In situations like this, you can consult a good reference.
std::vector provides operator[] with constant-time performance:
auto tenth_element = vehicle_vector[9];
std::unordered_set is optimised for element-based lookup (that is, testing whether an element is present or not). It is rare you would need the 10th element (especially since the set is, by definition, unordered), but if you do, you take an iterator, increment it and dereference it:
auto tenth_element = *std::next(vehicle_set.begin(), 9);
In general, you access the elements of a container either through the container's member functions (such as the vector's operator [] above), or through an iterator.
An iterator is a generalisation of a pointer - it's some unspecified type which points to an element in the container. You can then work with iterators using their member functions like operator ++ or free functions like std::next(). Random-access iterators also support []. To get the element to which the iterator "points," dereference the iterator like *it or it->whatever.
You obtain an iterator to the beginning of the container using begin() and an iterator to one past the last element using end(). Containers can also provide other member functions to get an iterator to an element - such as vehicle_set.find(aVehicle), which returns an iterator to aVehicle if it's present in the set, or the end() iterator if it's not.
Which member functions a container offers depends on which container it is and in particular how efficient the operations are. std::vector doesn't proivde find(), because it would be no better than std::find() - there is no structure in std::vector for fast lookup. std::unordered_set does provide find(), but doesn't have operator [], because its iterators are not random-access: accessing the nth element of an unordered set requires time proportional to n.

Generic operations on C++ containers

How to write generic operations on C++ STL containers? For example, Java has Collection interface, which every Java containers (except for maps) implements. I can do operations like add, remove, contains, and iterations regardless of whether the actual container is LinkedList, HashSet, ArrayBlockingQueue, etc. I find it very powerful.
C++ has iterators, but what about operations like add and remove?
vector has push_back, set has insert, queue has push. How to add something to C++ container in a generic way?
Iteration:
All standard containers have iterators which give ordered access to the elements of the containers. These can also be used in generic algorithms which work on any conforming iterator type.
Insertion:
All sequences and associative containers can have elements inserted into them by the expression c.insert(i, x) -- where c is a sequence or associative container, i is an iterator into c and x is a value that you want to add to c.
std::inserter and friends can be used to add elements to a sequence or associative container in a generic way.
Removal:
For any sequence or associative container the following code works:
while (true) {
X::iterator it(std::find(c.begin(), c.end(), elem));
if (it == c.end()) break;
c.erase(it);
}
Where X is the type of the container, c is a container object and elem is an object with the value that you want to remove from the container.
For sequences there is the erase-remove idiom, which looks like:
c.erase(std::remove(c.begin(), c.end(), elem), c.end());
For associative containers you can also do:
c.erase(k);
Where k is a key corresponding to the element that you want to erase.
A nice interface to all of this:
See Boost.Range.
Note -- these are compile time substitutable, whereas the java ones are run time substitutable. To allow run-time substitution it is necessary to use type erasure (that is -- make a templated sub-class that forwards the required interface to the container that it is instantiated with).
Look at the header <algorithm>. There are plenty of generic algorithms in there for finding, sorting, counting, copying, etc, that work on anything providing iterators with various specified characteristics.
C++ has std::inserter and friends to add elements to a container in a generic way. They are in the header file iterator.

Understanding Iterators in the STL

What exactly are iterators in the C++ STL?
In my case, I'm using a list, and I don't understand why you have to make an iterator std::list <int>::const_iterator iElementLocator; to display contents of the list by the derefrence operator:
cout << *iElementLocator; after assigning it to maybe list.begin().
Please explain what exactly an iterator is and why I have to dereference or use it.
There are three building blocks in the STL:
Containers
Algorithms
Iterators
At the conceptual level containers hold data. That by itself isn't very useful, because you want to do something with the data; you want to operate on it, manipulate it, query it, play with it. Algorithms do exactly that. But algorithms don't hold data, they have no data -- they need a container for this task. Give a container to an algorithm and you have an action going on.
The only problem left to solve is how does an algorithm traverse a container, from a technical point of view. Technically a container can be a linked list, or it can be an array, or a binary tree, or any other data structure that can hold data. But traversing an array is done differently than traversing a binary tree. Even though conceptually all an algorithm wants is to "get" one element at a time from a container, and then work on that element, the operation of getting the next element from a container is technically very container-specific.
It appears as if you'd need to write the same algorithm for each container, so that each version of the algorithm has the correct code for traversing the container. But there's a better solution: ask the container to return an object that can traverse over the container. The object would have an interface algorithms know. When an algorithm asks the object to "get the next element" the object would comply. Because the object came directly from the container it knows how to access the container's data. And because the object has an interface the algorithm knows, we need not duplicate an algorithm for each container.
This is the iterator.
The iterator here glues the algorithm to the container, without coupling the two. An iterator is coupled to a container, and an algorithm is coupled to the iterator's interface. The source of the magic here is really template programming. Consider the standard copy() algorithm:
template<class In, class Out>
Out copy(In first, In last, Out res)
{
while( first != last ) {
*res = *first;
++first;
++res;
}
return res;
}
The copy() algorithm takes as parameters two iterators templated on the type In and one iterator of type Out. It copies the elements starting at position first and ending just before position last, into res. The algorithm knows that to get the next element it needs to say ++first or ++res. It knows that to read an element it needs to say x = *first and to write an element it needs to say *res = x. That's part of the interface algorithms assume and iterators commit to. If by mistake an iterator doesn't comply with the interface then the compiler would emit an error for calling a function over type In or Out, when the type doesn't define the function.
I'm being lazy. So I would not type describing what an iterator is and how they're used, especially when there're already lots of articles online that you can read yourself.
Here are few that I can quote for a start, proividing the links to complete articles:
MSDN says,
Iterators are a generalization of
pointers, abstracting from their
requirements in a way that allows a
C++ program to work with different
data structures in a uniform manner.
Iterators act as intermediaries
between containers and generic
algorithms. Instead of operating on
specific data types, algorithms are
defined to operate on a range
specified by a type of iterator. Any
data structure that satisfies the
requirements of the iterator may then
be operated on by the algorithm. There
are five types or categories of
iterator [...]
By the way, it seems the MSDN has taken the text in bold from C++ Standard itself, specifically from the section §24.1/1 which says
Iterators are a generalization of
pointers that allow a C + + program to
work with different data structures
(containers) in a uniform manner. To
be able to construct template
algorithms that work correctly and
efficiently on different types of data
structures, the library formalizes not
just the interfaces but also the
semantics and complexity assumptions
of iterators. All iterators i support
the expression *i, resulting in a
value of some class, enumeration, or
built-in type T, called the value type
of the iterator. All iterators i for
which the expression (*i).m is
well-defined, support the expression
i->m with the same semantics as
(*i).m. For every iterator type X for
which equality is defined, there is a
corresponding signed integral type
called the difference type of the
iterator.
cplusplus says,
In C++, an iterator is any object
that, pointing to some element in a
range of elements (such as an array or
a container), has the ability to
iterate through the elements of that
range using a set of operators (at
least, the increment (++) and
dereference (*) operators).
The most obvious form of iterator is a
pointer [...]
And you can also read these:
What Is an Iterator?
Iterators in the Standard C++ Library
Iterator (at wiki entry)
Have patience and read all these. Hopefully, you will have some idea what an iterator is, in C++. Learning C++ requires patience and time.
An iterator is not the same as the container itself. The iterator refers to a single item in the container, as well as providing ways to reach other items.
Consider designing your own container without iterators. It could have a size function to obtain the number of items it contains, and could overload the [] operator to allow you to get or set an item by its position.
But "random access" of that kind is not easy to implement efficiently on some kinds of container. If you obtain the millionth item: c[1000000] and the container internally uses a linked list, it will have to scan through a million items to find the one you want.
You might instead decide to allow the collection to remember a "current" item. It could have functions like start and more and next to allow you to loop through the contents:
c.start();
while (c.more())
{
item_t item = c.next();
// use the item somehow
}
But this puts the "iteration state" inside the container. This is a serious limitation. What if you wanted to compare each item in the container with every other item? That requires two nested loops, both iterating through all the items. If the container itself stores the position of the iteration, you have no way to nest two such iterations - the inner loop will destroy the working of the outer loop.
So iterators are an independent copy of an iteration state. You can begin an iteration:
container_t::iterator i = c.begin();
That iterator, i, is a separate object that represents a position within the container. You can fetch whatever is stored at that position:
item_t item = *i;
You can move to the next item:
i++;
With some iterators you can skip forward several items:
i += 1000;
Or obtain an item at some position relative to the position identified by the iterator:
item_t item = i[1000];
And with some iterators you can move backwards.
And you can discover if you've reached beyond the contents of the container by comparing the iterator to end:
while (i != c.end())
You can think of end as returning an iterator that represents a position that is one beyond the last position in the container.
An important point to be aware of with iterators (and in C++ generally) is that they can become invalid. This usually happens for example if you empty a container: any iterators pointing to positions in that container have now become invalid. In that state, most operations on them are undefined - anything could happen!
An iterator is to an STL container what a pointer is to an array. You can think of them as pointer objects to STL containers. As pointers, you will be able to use them with the pointer notation (e.g. *iElementLocator, iElementLocator++). As objects, they will have their own attributes and methods (http://www.cplusplus.com/reference/std/iterator).
There already exists a lot of good explanations of iterators. Just google it.
One example.
If there is something specific you don't understand come back and ask.
I'd suggest reading about operator overloading in C++. This will tell why * and -> can mean essentially anything. Only then you should read about the iterators. Otherwise it might appear very confusing.

Why does vector not have sort() method as a member function of vector, while list does?

There is a sort() method for lists in STL. Which is absurd, because I would be more inclined to sort an array/vector.
Why isn't sort() provided for vector? Is there some underlying philosophy behind the creation of the vector container or its usage, that sort is not provided for it?
As has already been said, the standard library provides a nonmember function template that can sort any range given a pair of random access iterators.
It would be entirely redundant to have a member function to sort a vector. The following would have the same meaning:
std::sort(v.begin(), v.end());
v.sort();
One of the first principles of the STL is that algorithms are not coupled to containers. How data is stored and how data is manipulated should be as loosely coupled as possible.
Iterators are used as the interface between containers (which store data) and algorithms (which operate on the data). In this way, you can write an algorithm once and it can operate on containers of various types, and if you write a new container, the existing generic algorithms can be used to manipulate its contents.
The reason that std::list provides its own sort function as a member function is that it is not a random accessible container; it only provides bidirectional iterators (since it is intended to represent a doubly linked list, this makes sense). The generic std::sort function requires random access iterators, so you cannot use it with a std::list. std::list provides its own sort function in order that it can be sorted.
In general, there are two cases in which a container should implement an algorithm:
If the generic algorithm cannot operate on the container, but there is a different, container-specific algorithm that can provide the same functionality, as is the case with std::list::sort.
If the container can provide a specific implementation of the algorithm that is more efficient than the generic algorithm, as is the case with std::map::find, which allows an element to be found in the map in logarithmic time (the generic std::find algorithm performs a linear search because it cannot assume the range is sorted).
There are already interesting elements of answer, but there is actually more to be said about the question: while the answer to "why doesn't std::vector has a sort member function?" is indeed "because the standard library provides member functions only when they offer more than generic algorithms", the real interesting question is "why does std::list have a sort member function?", and a few things haven't been explained yet: yes, std::sort only works with random-access iterators and std::list only provides bidirectional iterators, but even if std::sort worked with bidirectional iterators, std::list::sort would still offer more. And here is why:
First of all, std::list::sort is stable, while std::sort isn't. Of course there is still std::stable_sort, but it doesn't work with bidirectional iterators either.
std::list::sort generally implements a mergesort, but it knows that it is sorting a list and can relink nodes instead of copying things. A list-aware mergesort can sort the list in O(n log n) time with only O(log n) additional memory, while your typical mergesort (such as std::stable_sort) uses O(n) additional memory or has a O(n log² n) complexity.
std::list::sort doesn't invalidate the iterators. If an iterator was pointing to a specific object in the list, it will still be pointing to the same object after the sort, even if its position in the list isn't the same than before the sort.
Last but not least, std::list::sort doesn't move or swap the objects around since it only relinks nodes. That means that it might be more performant when you need to sort objects that are expensive to move/swap around, but also that it can sort a list of objects that aren't even moveable, which is totally impossible for std::sort!
Basically, even if std::sort and std::stable_sort worked with bidirectional or forward iterators (and it would totally be possible, we know sorting algorithms that work with them), they still couldn't offer everything std::list::sort has to offer, and they couldn't relink nodes either since the standard library algorithms aren't allowed to modify the container, only the pointed values (relinking nodes counts as modifying the container). On the other hand, a dedicated std::vector::sort method wouldn't offer anything interesting, so the standard library doesn't provide one.
Note that everything that has been said about std::list::sort is also true for std::forward_list::sort.
A vector-specific sort would provide no advantage over std::sort from <algorithm>. However, std::list provides its own sort because it can use the special knowledge of how list is implemented to sort items by manipulating the links instead of copying objects.
You can easily sort a vector with:
sort(v.begin(), v.end());
UPDATE: (answer to the comment): Well, they have certainly provided it by default. The difference is that it's not a member function for vector. std::sort is a generic algorithm that's supposed to work for anything that provides iterators. However, it really expects a random access iterator to sort efficiently. std::list, being a linked list, cannot provide random access to its elements efficiently. That's why it provides its own specialized sort algorithm.
std::sort() in <algorithm> does sorting on containers with random access iterators like std::vector.
There is also std::stable_sort().
edit - why does std::list have its own sort() function versus std::vector?
std::list is different from both std::vector and std::deque (both random access iterable) in how it's implemented, so it contains its own sort algorithm that is specialized for its implementation.
Answering the question of "Why?"
A sorting algorithm for std::vector is the same as sorting a native array and is the same (probably) as sorting a custom vector class.
The STL was designed to separate containers and algorithms, and to have an efficient mechanism for applying an algorithm to data that has the right characteristics.
This lets you write a container that might have specific characteristics, and to get the algorithms free. Only where there is some special characteristic of the data that means the standard algorithm is unsuitable is a custom implementation supplied, as in the case of std::list.

Is there any reason that the STL does not provide functions to return an iterator via index?

Is there a reason that the STL does not provide functions to return an iterator into a container via an index?
For example, let's say I wanted to insert an element into a std::list but at the nth position. It appears that I have to retrieve an iterator via something like begin() and add n to that iterator. I'm thinking it would be easier if I could just get an iterator at the nth position with something like, std::list::get_nth_iterator(n).
I suspect I have misunderstood the principles of the STL. Can anyone help explain?
Thanks
BeeBand
You can use advance() from the <iterator> header:
list<foo>::iterator iter = advance(someFooList.begin(), n);
list<foo>::iterator iter = someFooList.begin();
std::advance( iter, n);
If the iterator supports random access (like vector) it'll work quite efficiently, if it only supports increasing (or decreasing) the iterator, like list, it'll work but only as well as can be.
std::list is a linked list. So it does not support random access. To get to the nth position in the list, you have to start at the beginning and move through all the nodes until you arrive at n. This is pretty expensive (O(n)), and thus it's bad to have a method that does not suggest this expense. get_nth_iterator(n) implies getting the iterator that points to the nth node is cheap.
std::vector of course supports this directly with the [] operator, because the datastructure supports random access and so this is very inexpensive for it.
std::list isn't random-access container, so there is no reason for accessing n-th element. if you need this, consider using std::vector instead..
Generally, anything that might be costly is made a bit clumsy, so you won't do it by accident. Using your example, with a container that provides random access iterators it would be simply container.begin()+n, but for an std::list (which provides a forward iterator) you'd need to use list.begin() followed by advance().
If you want to get the Nth iterator, chances are that you just shouldn't be using std::list in the first place. Then again, if you started that sentence at "chances", it would remain nearly as true...