How get non-const iterator - c++

std::map<char,int> dict;
...
auto pmax = dict.begin(); // here i get const iterator
Can I "explicitly indicate" that the value obtained is a non-constant type?

If your dict is not const, begin will return a std::map<char,int>::iterator. Now, the key is const, but the value is not.
auto should give you a std::map<char,int>::iterator; do you have evidence to the contrary?

Looking at your code, you are basically implementing std::max_element. So you could rewrite your last output line to:
std::cout << std::max_element(begin(dict), end(dict),
[](decltype(*begin(dict)) a, decltype(*begin(dict)) b) {
return a.second < b.second;
})->first << std::endl;
Admittedly, the decltype(*begin(dict)) is ugly, which hopefully will be remedied by generic lambdas in C++1y.
The point is, that regardless of whether you have a map::iterator or map::const_iterator when you dereference it, the result will be a std::pair with a const key_type as first argument. So, even if you have two iterators it1, it2 to mutable data (e.g., acquired via map::begin()), you can not re-assign the complete pair that is referenced by those iterators. Thus, *it1 = *it2 won't work, because you are trying to overwrite the mapped_type and the const key_type.

Related

Change/update value using std::map const_iterator

I am just curious to know if I can change/update the map's value using const_iterator.
Below is the code snippet:
int main()
{
map <int, int> m;
m.insert(make_pair(1, 10));
map <int, int>::const_iterator itr = m.begin(); //The iterator is const_iterator
itr->second = 30;
cout << itr->second; //The value to be printed is 30, and not 10.
return 0;
}
Thank you in advance for sharing your ideas.
The whole point of const_iterator is that it cannot be used to modify the container. So no.
It is not possible to change an element through a const iterator. That's the most important distinction between a const iterator and non-const iterator.
std::map::begin returns a non-const iterator (assuming the object operand is non-const), so there is no need to use a const iterator in the first place.
However, if for some reason (not demonstrated in the example) you can only have a const iterator, but have non-const access to the container, then you can get a non-const iterator to the element pointed by the const iterator. This can be achieved by using following, which looks like a trick:
map <int, int>::iterator mutable_itr = m.erase(itr, itr);
It doesn't erase anything, because [itr, itr) is an empty range.
Can I change/update the map's value using const_iterator?
No!
It's called const iterator for a reason. As mentioned here, A const_iterator is an iterator that points to const value (like a const T* pointer); dereferencing it returns a reference to a constant value (const T&) and prevents modification of the referenced value: it enforces const-correctness.
The compiler should not allow modifying the contents of a map through a const_iterator. The line
itr->second = 30;
should be reported as an error. If your compiler allows that line, then it is not standards compliant. Perhaphs it allows that line to be compiled through flags that allow standards-incompatible behavior.
Using g++, I get the following error.
socc.cc: In function ‘int main()’:
socc.cc:12:19: error: assignment of member ‘std::pair<const int, int>::second’ in read-only object
itr->second = 30;
const iterator is supposed to prevent the user from changing/modiyfing the value by any means.

understanding std::find_if() using a lamda on std::pair

It is my understanding that std::find_if() below returns an iterator to the first element in the range of arg for which the third argument (lamda function) returns true. Is that correct?
Could somebody explain why there isn't an iterator defined like this std::pair<std::string, std::type_index>::iterator = std::find_if(...)?
Where is the iterator returned by std::find_if() stored and how can you call ->second on its own and not on an iterator?
std::type_index argType(const std::string& name) const
{
return std::find_if(args_.begin(), args_.end(),
[&name](std::pair<std::string, std::type_index> arg)->bool
{
return arg.first == name;
}
)->second;
}
It is my understanding that std::find_if() below returns an iterator
Yes, but that iterator is then dereferenced within the same expression. The function returns a copy of the std::type_index from some element of args_, which is presumably some std-like container with a value_type of std::pair<std::string, std::type_index> (or similar).
At a guess it's a std::vector<std::pair<std::string, std::type_index>>, because if it were a map the whole function could be simplified to
return args_.at(name);
Could somebody explain why there isn't an iterator defined like this std::pair<std::string, std::type_index>::iterator = std::find_if(...)?
Well firstly std::pair doesn't have a member iterator. I assume you meant std::vector<std::pair<std::string, std::type_index>>::iterator (or whichever collection type args_ is).
There doesn't need to be a separate statement declaring such an iterator, in much the same way as you don't need a separate double in the statement
return floor(3.14 * radius);
when you want an integer circumference calculation.
Where is the iterator returned by std::find_if() stored
Anywhere the compiler likes. It only exists while the return statement is being evaluated.
how can you call ->second on its own
You aren't. You are calling it on the temporary returned by std::find_if
and why is there a != args_.end() after the closing brace of std::find_if?
There isn't. The author assumes that they will find a matching element. If they don't, the program has undefined behaviour. That may be intentional, or it may be a bug.

C++ vector iteration code doesn't compile, when vector is passed as reference-to-const

I have the following for loop, that iterates over a vector thats passed-by-reference-to-const
void PrintVector(const vector<string>& myVector) {
for(vector<string>::iterator itr = myVector.begin(); itr != myVector.end(); ++itr)
someFunctionThatTakesAPassByReferenceToConstParameter(itr);
}
The iterator itr is passed in as reference-to-const to the function someFunctionThatTakesAPassByReferenceToConstParameter(). Thus, it is guaranteed that this function will not change the iterator object. Even though this is guaranteed, why does the code not compile?
EDIT: I know I could use a const_iterator. But I'd like to know why this doesn't compile.
I know I could use a const_iterator. But I'd like to know why this
doesn't compile.
The vector class will have two different "begin" function (overloaded on constness). Something like:
const_iterator begin() const { return ...; }
and
iterator begin() { return ...; }
Since you have a const reference to the vector the former will be called and a const_iterator cannot be converted to a iterator (since the iterator would be able to modify the value "pointed" to).
You need
vector<string>::const_iterator itr = myVector.begin();
if myVector is a const reference.
use vector<string>::const_iterator, that is what begin() of a const vector returns.
You didn't include the compiler error, but this seems fairly obvious:
someFunctionThatTakesAPassByReferenceToConstParameter(itr);
Here, itr isn't a const string&, but a vector<string>::iterator. You need to dereference the iterator:
someFunctionThatTakesAPassByReferenceToConstParameter(*itr);
This post seems to be psudocode, but as mentioned elsewhere, you also should use const_iterator rather than iterator:
for(vector<string>::const_iterator itr = myVector.begin(); itr != myVector.end(); ++itr)
So others have pointed out what you have to use, which you seem to be uninterested in. Your other question in a comment was:
I could use that [i. e. const_iterator]. But I'd like to know why this doesn't compile.
The answer is: Because a non-const iterator can potentially be modified when dereferenced, and a reference to const object doesn't permit that.
You should pass *itr to pass the string.

When should I use the new ranged-for and can I combine it with the new cbegin/cend?

The new ranged-for in C++11 will be very concise and useful, of course. As far as I understand how it works, it looks up the "containers" begin and end by trying *Argument-Depending-Lookup" (ADT).
But another addition is that all the containers now have cbegin() and cend() to get the const_iterators for the container.
I am a bit confused, on the one hand I guess I should use cbegin() if I do not want to modify the container, on the other hand I have to add an additional const inside the ranged-for to get the same thing.
So, it looks like this:
// print all
for(const auto elem : data)
cout << elem
using ADT, finding data.begin(), thus const needed.
vs
// print everything but the first (a reason not to use range-for)
for(auto it = data.cbegin()+1; it!=data.cend(); ++it)
cout << *it
using data.cbegin(), thus no const needed.
But would this not be more "idiomatic"?:
// print everything but the first (a reason not to use range-for)
for(const auto it = data.begin()+1; it!=data.end(); ++it)
cout << *it
Did I get the "idiom" right? Any additions?
When should I use cbegin?
Do I miss something with ranged-for, looking for begin() only?
Edit: correction of error Value vs Iterator
cbegin() allows you to get const_iterators from a non-const container without an explicit cast or conversion. If you have a const container then begin() will return a const_iterator anyway.
The new for construct uses begin() because that's the most general, and it avoids too many special cases. Also, by default, the variable is a value, not an iterator or a reference.
std::vector<int> v;
for(auto i: v) // i is an int
dostuff(i);
This avoids the problem of modifying the container, as the element is copied. To get a reference you need to declare it:
for(auto &i: v)
dostuff(i);
I would use cbegin/cend in in the for loop if the intention is not to modify the elements in the range. That's the obvious reason for adding them in the first place.
This is hardly idiomatic yet, as the new standard isn't even off the presses!

What is the difference between const_iterator and non-const iterator in the C++ STL?

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 .