Generic operations on C++ containers - c++

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.

Related

Why isn't there a named requirement ordered container in C++?

Many STL containers have both ordered and unordered version, e.g. map and unondered_map, set and unordered_set. And on the other hand, some STL algorithms have to be fed in an ordered container to give the correct output. For instance, std::set_difference will not work correctly on unordered_set. So my question is, why isn't there a named requirement that specifies a container is always sorted, such that inputs to algorithms like set_difference are constraint to those sorted containers?
In a way, the STL concept contradicts the original idea of
object-oriented programming: The STL separates data and algorithms
rather than combining them. However, the reason for doing so is very
important. In principle, you can combine every kind of container with
every kind of algorithm, so the result is a very flexible but still
rather small framework.
-- from Nicolai M. Josuttis <<The C++ Standard Library A Tutorial and Reference Second Edition>>
There are three classes of STL containers :
sequence containers(array, vector, deque, forward_list, list)
associative containers(set, map, multiset, and multimap)
unordered associative containers(unordered_set, unordered_map, unordered_multiset, and unordered_multimap)
You can get sorted sequence containers by calling std::sort for array, vector, deque, sort() member function for forward_list and list.

Why is a vector used while defining priority queue of structures?

I know that we can define a priority queue of structures in the following way -
std::priority_queue<somestructure, vector<somestructure>, compare> pq;
Where compare is the structure which contains the compare function. I want to ask why we need to use vector as the second argument in this declaration. How is a vector related to a priority queue while defining the above priority queue?
std::priority_queue is what we call a container adapter. As you know in C++ we got containers like std::vector, std:array or std::deque. All those are there to directly save stuff of type T into them, with different pros and cons.
std::stack for example is a container adapter, which can be used on top of std:deque. The only thing this adapter does is to take away the functionality of std::deque to insert at the end, or take from the end. By this the user is forced to use the std::deque only like a stack.
Something similiar is true for std::priority_queue, it forces you to only insert into the underlying container, a std::vector for example, in an order. By this you get some nice properties of how to find elements in this container. In this special case, by taking more effort into how to insert new elements in the underlying container, and taking away the freedom to randomly insert an element anywhere you like. So you got O(log(n)) complexity for the insert instead of O(1) (instead of inserting at the end for example). But by that you have a complexity of only O(1) to find the largest element, instead of O(n).
There is nothing special about std::vector in this case, you could use any container that satisfy the needs of this container adaptor, you could also use std::deque or your own container or to quote:
The type of the underlying container to use to store the elements.
The container must satisfy the requirements of SequenceContainer, and
its iterators must satisfy the requirements of
LegacyRandomAccessIterator. Additionally, it must provide the
following functions with the usual semantics: front() push_back()
pop_back() The standard containers std::vector and std::deque satisfy
these requirements.

Retrieve container's comparison function given an iterator

Given an iterator, is it possible to retrieve/use the correct comparison function for the collection that this iterator refers to?
For example, let's assume I'm writing a generic algorithm:
template <class InIt, class T>
void do_something(InIt b, InIt e, T v) {
// ...
}
Now, let's say I want to do something simple, like find v in [b..e). If b and e are iterators over a std::vector, I can simply use if (*b == v) .... Let's assume, however, that b and e are iterators over a std::map. In this case, I should only compare the keys, not the whole value type of what's contained in the map.
So the question is, given those iterators into the map, how do I retrieve that map's comparison function that will only compare the keys? At the same time, I don't want to blindly assume that I'm working with a map either. For example, if the iterators pointed to a set, I'd want to use the comparison function defined for that set. If they pointed to a vector or deque, I'd probably have to use ==, because those containers won't have a comparison function defined.
Oh, almost forgot: I realize that in many cases, a container will only have an equivalent of operator< rather than operator== for the elements it contains -- I'm perfectly fine with being able to use that.
Iterators don't have to be connected to containers, so they don't give you any details about the containers that they aren't necessarily connected to. That's the essential iterator abstraction: iterators delimit sequences, without regard to where the sequence comes from. If you need to know about containers you have to write algorithms that take containers.
There is no standard way to map from an iterator to the underlying container type (if there is such a container at all). You might be able to use some heuristics to try to determine which container, although that will not be simple and probably not guaranteed either.
For example, you can use a metafunction to determine whether the *value_type* is std::pair<const K, T>, which is a hint that this could be a std::map and after extracting the types K and T try to use a metafunction to determine whether the type of the iterator and the type of std::map<K,T,X,Y>::iterator or std::map<K,T,X,Y>::const_iterator match for a particular combination of X, Y.
In the case of the map that could be sufficient to determine (i.e. guess with a high chance of success) that the iterator refers to a std::map, but you should note that even if you can use that and even extract the type X of the comparator, that is not sufficient to replicate the comparator in the general case. While uncommon (and not recommended) comparators can have state, and you would not know which is the particular state of the comparator without having access to the container directly. Also note that there are cases where this type of heuristic will not even help, in some implementations of std::vector<> the iterator type is directly a pointer, and in that case you cannot differentiate between an 'iterator' into an array and an iterator into a std::vector<> of the same underlying types.
Unfortunately iterators don't always know about the container that contains them (and sometimes they aren't in a standard container at all). Even the iterator_traits only have information about the value_type which doesn't specifically tell you how to compare.
Instead, let's draw inspiration from the standard library. All the associative containers (map, etc) have their own find methods rather than using std::find. And if you do need to use std::find on a such a container, you don't: you use find_if.
It sounds like your solution is that for associative containers you need a do_something_if that accepts a predicate telling it how to compare the entries.

C++ reverse_iterator Alternatives

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.

why there is no find for vector in C++

what's the alternative?
Should I write by myself?
There is the std::find() algorithm, which performs a linear search over an iterator range, e.g.,
std::vector<int> v;
// Finds the first element in the vector that has the value 42:
// If there is no such value, it == v.end()
std::vector<int>::const_iterator it = std::find(v.begin(), v.end(), 42);
If your vector is sorted, you can use std::binary_search() to test whether a value is present in the vector, and std::equal_range() to get begin and end iterators to the range of elements in the vector that have that value.
The reason there is no vector::find is because there is no algorithmic advantage over std::find (std::find is O(N) and in general, you can't do better for vectors).
But the reason you have map::find is because it can be more efficient (map::find is O(log N) so you would always want to use that over std::find for maps).
Who told you that? There's is "find" algorithm for vector in C++. Ironically Coincidentally, it is called std::find. Or maybe std::binary_search. Or something else, depending on the properties of the data stored in your vector.
Containers get their own specific versions of generic algorithms (implemented as container methods) only when the effective implementation of the algorithm is somehow tied to the internal details of the container. std::list<>::sort would be one example.
In all other cases, the algorithms are implemented by standalone functions.
Having a 'find' functionality in the container class violates 'SRP' (Single Responsibility Principle). A container's core functionality is to provide interfaces for storage, retrieval of elements in the container. 'Finding', 'Sorting', 'Iterating' etc are not core functionality of any container and hence not part of it's direct interface.
However as 'Herb' states in Namespace Principle, 'find' is a part of the interface by being defined in the same namespace as 'vector' namely 'std'.
Use std::find(vec.begin(), vec.end(), value).
And don't forget to include <algorithm>
what's the alternative?
The standard offers std::find, for sequential search over arbitrary sequences of like-elements (or something like that).
This can be applied to all containers supporting iterators, but for internally sorted containers (like std::map) the search can be optimized. In that case, the container offers it's own find member function.
why there is no find for vector in C++?
There was no point in creating a std::vector<???>::find as the implementation would be identical to std::find(vector.begin(), vector.end(), value_to_find);.
Should I write by myself?
No. Unless you have specific limitations or requirements, you should use the STL implementation whenever possible.