Classification of std::vector's iterators - c++

In the description of std::vector on cppreference (http://en.cppreference.com/w/cpp/container/vector/begin), I miss the categorization of the iterator (according to http://www.cplusplus.com/reference/iterator/) that is returned by the begin() function (the same applies for the iterator returned by end()).
Does cppreference not have to state which category of iterator is returned by begin() so that the user knows the iterator's functionality?
Currently, for me, it remains unclear which functionality std::vector's iterators provide.

Look at the main desciption of std::vector under the section Member types:
iterator RandomAccessIterator
const_iterator Constant random access iterator
reverse_iterator std::reverse_iterator<iterator>
const_reverse_iterator std::reverse_iterator<const_iterator>
std::vector uses RandomAccessIterator
A RandomAccessIterator is a BidirectionalIterator that can be moved to
point to any element in constant time. A pointer to an element of an
array satisfies all requirements of RandomAccessIterator
...

On the cppreference page for std::vector you will find:
Member types
============
...
iterator RandomAccessIterator

From here http://en.cppreference.com/w/cpp/container/vector you can see that a vector's iterators model the RandomAccessIterator concept: http://en.cppreference.com/w/cpp/concept/RandomAccessIterator
std::vector::begin() returns a std::vector::iterator (or const_iterator)
std::begin(x) returns the result of x.begin()
Therefore std::begin(std::vector<...>) will return a random access iterator.

Related

Is it legal to use the insert member function to insert a range into an empty vector? [duplicate]

This question already has answers here:
Is begin() == end() for any empty() vector?
(4 answers)
Closed 2 years ago.
Is it legal to insert into the std::vector named myvec when it is empty? Like so:
myvec.insert(myvec.end(), other.begin(), other.end());
I'm not sure where myvec.end() would point in that case.
Also, when myvec is empty, is the above different from the following?
myvec.insert(myvec.begin(), other.begin(), other.end());
Are any of these legal?
C++20 final working draft 22.2.1 General container requirements [container.requirements.general]
begin() returns an iterator referring to the first element in the
container. end() returns an iterator which is the past-the-end value
for the container. If the container is empty, then begin() == end().
Yes they are the same. Are they legal?
From cppreference on std::vector insert
template< class InputIt >
void insert( iterator pos, InputIt first, InputIt last);
Is iterator pos valid? (i.e. std::begin of an empty vector). Yes it is, but you shall not dereference it.
Yes, it's perfectly legal. From cppreference:
Causes reallocation if the new size() is greater than the old capacity(). If the new size() is greater than capacity(),
when myvec is empty, is the above different from the following?
No, because when a vector is empty, vector::begin() == vector::end(). So they are both same.
By definition a container is empty when begin() == end(). See this answer for details. In other words, end() and begin() can be used on an empty container (though you cannot dereference them). Consequently, an empty vector does not constitute a special case when calling algorithms. If
myvec.insert(myvec.end(), other.begin(), other.end());
is fine with myvec that has elements, then it is also fine for an empty myvec (also whether other has elements or not does not require extra handling on that call).

Are const iterators still evil in C++14

Item 26 from Scott Mayers's "Effective STL" is labeled "Prefer iterator to const_iterator, reverse_iterator and const reverse iterator".
The reasoning is that some forms of insert() and erase() require exactly iterator and converting from the other types is tedious and error-prone. Furthermore, comparing iterator and const_iterator could be problematic, depending on the STL implementation.
The book was released at 2001. Is the advice in Item 26 still valid with the current state of gcc?
The C++14 standard (N3936) guarantees that iterator and const_iterator are freely comparable (§23.2.1 [container.requirements.general]/p7):
In the expressions
i == j
i != j
i < j
i <= j
i >= j
i > j
i - j
where i and j denote objects of a container’s iterator type,
either or both may be replaced by an object of the container’s
const_iterator type referring to the same element with no change in
semantics.
In addition, the container member functions take const_iterator parameters as of C++11 (§C.2.13 [diff.cpp03.containers] - as might be inferred from the tag, this is a change from C++03):
Change: Signature changes: from iterator to const_iterator parameters
Rationale: Overspecification. Effects: The signatures of the following member functions changed from taking an iterator to taking
a const_iterator:
insert(iter, val) for vector, deque, list, set, multiset, map, multimap
insert(pos, beg, end) for vector, deque, list, forward_list
erase(iter) forset,multiset,map,multimap`
erase(begin, end) forset,multiset,map,multimap`
all forms of list::splice
all forms of list::merge
The container requirements have been similarly changed to take const iterators. In addition, it is easy to obtain the underlying iterator from a std::reverse_iterator via its .base() member function. Thus, neither of the concerns noted in the question should be an issue in a conforming compiler.
The advice has been reversed, as can be seen from Item 13 of the upcoming Effective Modern C++ which is titled:
Prefer const_iterators to iterators
The reason is that C++11 and C++14 add several tweaks that make const_iterators a lot more practical:
C++11 adds
member functions cbegin() and cend() (and their reverse counterparts) for all Standard Library containers
member functions using iterators to identify positions (e.g. insert(), erase()) now take a const_iterator instead of an iterator
C++14 completes that by adding non-member cbegin() and cend() (and their reverse counterparts)

what is the iterator type of map<T, U>.begin()

template <class InputIterator, class Distance>
void advance (InputIterator& it, Distance n);
InputOutput < Forward < Bidirectional < Random Access
map<int, int> mapInts;
...
std::map<int, int>::iterator it = mapInts.begin();
std::advance (it,5);
Q> What is the type of iterator the map.begin returns? InputOut, Forward, Bidirectional?
Thank you
From Map::begin() documentation
std::map.begin()
Return iterator to beginning
Returns an iterator referring to the first element in the map container.
Because map containers keep their elements ordered at all times, begin points to the element that goes first following the container's sorting criterion.
If the container is empty, the returned iterator value shall not be dereferenced.
Return Value:
An iterator to the first element in the container.
If the map object is const-qualified, the function returns a const_iterator. Otherwise, it returns an iterator.
Member types iterator and const_iterator are bidirectional iterator types pointing to elements (of type value_type).
Notice that value_type in map containers is an alias of pair.
EDIT: by courtesy of #Andy Prowl:
Per C++ standard § 23.2.4/6
iterator of an associative container is of the bidirectional iterator category

std::equal with reverse_iterator

Is it legal to use a reverse_iterator with std::equal?
For example, are any of these legal?
std::equal(v.begin(), v.end(), w.rbegin())
std::equal(v.rbegin(), v.rend(), w.begin())
std::equal(v.rbegin(), v.rend(), w.rbegin())
All are valid, because reverse iterators are, in fact, forward iterators.
"Reverse iterator" is not an iterator category.
Remember some iterator categories:
An iterator that can be dereferenced (*) and incremented (++) is a forward iterator.
A forward iterator that can also be decremented is a bidirectional iterator.
A random access iterator is a biderectional iterator that also has + and - operators.
On the other hand, a reverse iterator is a bidirectional iterator or a random access iterator that looks at a collection in reverse. Look at
http://www.cplusplus.com/reference/std/iterator/reverse_iterator/
... especially what it says about iterator_category under the "Member types" heading.

What to return for 'begin' and 'end' functions for my vector wrapper, for iterators?

I have a class called PointList, which holds a vector of Point * objects as its main data. I want to iterate over the points the same way you would a vector, kind of like this:
for (vector<Point *>::iterator it = point_list->begin(); it != point_list->end(); ++it)
Clearly the begin() and end() functions I write can just return the vector's begin/end functions that they hold, but what is the return type of these functions?
If I have understood the question right, the answer is right in your question. You already use the return value and type of begin and end in your piece of code.
vector<Point *>::iterator it = point_list->begin();
clearly, it holds the return value of begin() and its type is well known:
vector<Point *>::iterator
By the way, a little off-topic - why point_list is pointer to vector, not an object? And second, why it's called list, as it's vector? Use vector, or array, or sequence, but not list, as it could be misleading. list is a STL container, different from vector.
Their return type would be vector<Point *>::iterator.
You should copy the container interface, by providing two iterator types, three begin functions and three end functions. The most obvious iterator types to use are taken straight from the vector:
struct PointList {
typedef std::vector<Point*>::iterator iterator;
typedef std::vector<Point*>::const_iterator const_iterator;
iterator begin();
const_iterator begin() const;
const_iterator cbegin() const;
iterator end();
const_iterator end() const;
const_iterator cend() const;
};
cbegin() and cend() are new to C++11, they aren't in C++03. The idea is that since they don't have a non-const overload, the user can call them on a non-const container in preference to messing about with a conversion.
Since the underlying storage is in a vector, you might also consider providing (c)rbegin() and (c)rend(). In fact to implement the standard container interface you'd have to, since your iterator type is random-access. If you don't want to do that (perhaps because some future implementation of this class will not necessarily use a vector, but some other container underneath), then there is an argument for wrapping the vector's iterator in a class of your own just as you've wrapped the vector in a class of your own. That's extra work that's only needed if you need to prevent users from relying on properties of the iterator that could disappear in future implementations. You might not care about this in an internal API, more so in a published one.
They are of type vector<Point *>::iterator just like your it object. But why do you want to iterate your data outside of the container object? That would be violation of encapsulation no?