https://en.cppreference.com/w/cpp/container/vector/insert
Cppreference shows: iterator insert( const_iterator pos, const T& value ); and four other overloads.
But why the parameter is const_iterator but not iterator?
Whether or not the iterator is const doesn't matter, since the container is the thing being modified (and insert is not a const-qualified member function), not the passed in iterator.
And this just makes it easier to use. A non-const iterator is convertible to a const_iterator (but not the other way around) so you can still easily use an iterator.
A somewhat relevant paper: https://wg21.link/N2350
Related
Why for there is non-const find() in std::unordered_set()?
iterator find( const Key& key );
const_iterator find( const Key& key ) const;
iterator is the same as const_iterator, why there is non-const version of find()?
http://en.cppreference.com/w/cpp/container/unordered_set/find
iterator is the same as const_iterator, why there is non-const version of find()?
Because iterator is not mandatory the same as const_iterator, as stated in documentation:
The member types iterator and const_iterator may be aliases to the same type. Since iterator is convertible to const_iterator, const_iterator should be used in function parameter lists to avoid violations of the One Definition Rule.
emphasis is mine. Since they are not mandatory the same some generic code can depend on particular type of iterator returned by find() and it should be consistent with other containers.
If I have a vector that contains iterators of another vector.
For example :
vector<vector<int>::iterator> vec;
what happens when passing this vector in const refrence?
For example:
void fun(const vector<vector<int>::iterator> &vec);
Are the elements of vec inside function fun const_iterator or iterator? can they be modified
Thanks in advance!
No, they aren't const_iterator. Chiefly because const_iterator is a user defined type that is related to iterator via a user defined conversion, and not in fact a const qualified iterator. (1)
What you access inside the function through the vector are const iterator&.
So you can use those to modify the elements referred by them.
The best analogy to this is that const_iterator is to iterator, what const T* is to T*. And what you have inside your function is akin to T * const.
(1) On paper, that is. For vectors it may very well be plain pointers in optimized code. In which case the analogy becomes the reality.
Take any STL container in mind which uses iterators.
The following is valid:
iterator begin();
const_iterator begin() const;
const_iterator cbegin() const;
Now I don't understand why the second line exists. Could someone provide a nice example where iterator begin(); wouldn't work and it can't be replaced by const_iterator cbegin();... begging the need for const_iterator begin();?
First off, there is a simple historic reason: the original C++ standard didn't use cbegin() and only had the two begin() overloads. It was felt that sometimes it would be useful to obtain const_iterators to a non-const sequence and cbegin() and cend() were added (despite begin() and end() members actually being ill-advise: we'd be much better of if they were just non-member functions). That is, if the const overload of begin() had been removed when cbegin() was introduced, at lot of code would have been broken.
From a practical point of view it is also desirable to have both the non-const and the const overloads:
use of begin() and cbegin() in normal code could be done it would be quite annoying to actually do so when changing the constness of objects
more importantly, in generic (templatized) code where sequence could be either const or non-const it would be necessary to use some dance to to use the correct overload.
There's probably no place in the language where you couldn't give something a different name; this is just a little act of kindness, a bit like size() and length() on std::string.
Remembering to use cbegin when working on a const container is a PITA, so the const_iterator begin() const is useful. At the same time, when I'm explicitly interested in obtaining a const iterator, without cbegin I'd have to do something convoluted like ((const std::vector<int> &)vec).begin(), which is certainly less readable/writable than vec.cbegin().
Now, you could argue that there are places where little acts of kindness like this are more sorely needed (and which scale better — supporting all the combinations of regular/reverse/const iterators quickly makes the interface explode), and I would certainly agree with you.
Incidentally, having the const_iterator begin avoids the need for other fiddling to make the range-based for loop work correctly on const objects.
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?
What is the difference between a const_iterator and an iterator and where would you use one over the other?
const_iterators don't allow you to change the values that they point to, regular iterators do.
As with all things in C++, always prefer const, unless there's a good reason to use regular iterators (i.e. you want to use the fact that they're not const to change the pointed-to value).
They should pretty much be self-explanatory. If iterator points to an element of type T, then const_iterator points to an element of type 'const T'.
It's basically equivalent to the pointer types:
T* // A non-const iterator to a non-const element. Corresponds to std::vector<T>::iterator
T* const // A const iterator to a non-const element. Corresponds to const std::vector<T>::iterator
const T* // A non-const iterator to a const element. Corresponds to std::vector<T>::const_iterator
A const iterator always points to the same element, so the iterator itself is const. But the element it points to does not have to be const, so the element it points to can be changed.
A const_iterator is an iterator that points to a const element, so while the iterator itself can be updated (incremented or decremented, for example), the element it points to can not be changed.
Unfortunaty, a lot of the methods for the STL containers takes iterators instead of const_iterators as parameters. So if you have a const_iterator, you can't say "insert an element before the element that this iterator points to" (saying such a thing is not conceptually a const violation, in my opinion). If you want do that anyway, you have to convert it to a non-const iterator using std::advance() or boost::next(). Eg. boost::next(container.begin(), std::distance(container.begin(), the_const_iterator_we_want_to_unconst)). If container is a std::list, then the running time for that call will be O(n).
So the universal rule to add const wherever it is "logical" to do so, is less universal when it comes to STL containers.
However, boost containers take const_iterators (eg. boost::unordered_map::erase()). So when you use boost containers you can be "const agressive". By the way, do anyone know if or when the STL containers will be fixed?
Minimal runnable examples
Non-const iterators allow you to modify what they point to:
std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);
Const iterators don't:
const std::vector<int> v{0};
std::vector<int>::const_iterator cit = v.begin();
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;
As shown above, v.begin() is const overloaded, and returns either iterator or const_iterator depending on the const-ness of the container variable:
How does begin() know which return type to return (const or non-const)?
how does overloading of const and non-const functions work?
A common case where const_iterator pops up is when this is used inside a const method:
class C {
public:
std::vector<int> v;
void f() const {
std::vector<int>::const_iterator it = this->v.begin();
}
void g(std::vector<int>::const_iterator& it) {}
};
const makes this const, which makes this->v const.
You can usually forget about it with auto, but if you starting passing those iterators around, you will need to think about them for the method signatures.
Much like const and non-const, you can convert easily from non-const to const, but not the other way around:
std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
// non-const to const.
std::vector<int>::const_iterator cit = it;
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;
// Compile time error: no conversion from const to no-const.
//it = ci1;
Which one to use: analogous to const int vs int: prefer const iterators whenever you can use them (when you don't need to modify the container with them), to better document your intention of reading without modifying.
Use const_iterator whenever you can, use iterator when you have no other choice.
(as others have said) const_iterator doesn't allow you modify the elements to which it points, this is useful inside of const class methods. It also allows you to express your intent.
ok Let me explain it with very simple example first without using constant iterator
consider we have collection of random integers collection "randomData"
for(vector<int>::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0;
for(vector<int>::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i;
As can be seen for writing/editing data inside collection normal iterator is used but for reading purpose constant iterator has been used . If you try using constant iterator in first for loop you will get error . As a thumb rule use constant iterator to read data inside collection .