Considering this piece of c++ code. Why is the output of mp.end()->first the number of keys in the container.
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
map<int, char> mp;
mp[0]='a';
mp[1]='b';
mp[2]='c';
mp[3]='d';
mp[3]='e';
mp[7]='f';
map<int, char>::iterator itr = mp.end();
cout << itr->first << endl;
return 0;
}
The output for this code is 5.
Can someone explain this?
Probably the best answer is going to come from the reference
The end() function returns an iterator past the end of the map. Dereferencing it is undefined, so whatever output you see from this code is irrelevant.
What you probably want to do instead is look at end() - 1, in which case the result will be a std::pair of int and char giving you the key and value at that point in the map respectively (via members first and second). Have a look at that reference too.
Try this instead:
cout << (--itr)->first << endl;
as Jon Reeves said using an iterator and setting it to the map's end() for later dereferencing is undefined behavior and will bring you garbage. An also correct way to achieve what you want is the following:
map<int, char>::reverse_iterator itr = mp.rbegin();
cout << (*itr).first << endl;
This will return 7. If you want the letter or value use (*itr).second instead.
Related
I have the following code to randomize the elements in a list container:
#include <vector>
#include <list>
#include <iterator>
#include <algorithm>
#include <iostream>
using namespace std;
template<class RandomAccesIterator>
void randomize(RandomAccesIterator iterBegin, RandomAccesIterator iterEnd)
{
while (iterBegin != iterEnd)
{
iter_swap(iterBegin, iterBegin + rand() % (iterEnd - iterBegin));
++iterBegin;
}
}
And then later in main():
int main()
{
//container used as to apply algorithm to.
list<int> List = {34,77,16,2,35,76,18,2};
//randomize example.
cout << "calling randomize on sorted vector: " << endl;
List.sort();
vector<int> temp(List.begin(), List.end());
cout << "before randomize: " << endl;
for (vector<int>::iterator it = temp.begin(); it != temp.end(); it++)
{
cout << *it << " ";
}
cout << endl;
randomize(temp.begin(),temp.end());
cout << "after randomize: " << endl;
for (vector<int>::iterator it = temp.begin(); it != temp.end(); it++)
{
cout << *it << " ";
}
cout << endl<<endl;
return 0;
}
I had a couple of questions:
I believe performing iterEnd - iterBegin (as shown in the template function) is a valid operation, because both iterEnd and iterBegin are C++ style pointers. and subtracting these pointers gives the distance between them. Am I correct?
I tried the following in the immediate window:
iterEnd
{-33686019}
[ptr]: 0x00ba4f78 {-33686019}
[Raw View]: {...}
it means iterEnd is a pointer, whose value is 0x00ba4f78, and it points to the garbage value of -33686019. I believe I am correct here?
So, the iterator is a pointer, for random access iterators. Is it true for all iterator types (Input/output iterators, Forward iterators, BiDirectional iterators)? If those iterators are not C++ style pointers, then what are those?
I also tried the following in the immediate window:
&iterEnd
0x006ff368 {-33686019}
[ptr]: 0x00ba4f78 {-33686019}
[Raw View]: 0x006ff368 {...}
&&iterEnd
expected an expression
Why is &iterEnd giving me an address? It should give me the message "expected an expression", as, &&iterEnd does.
How are random access iterators implemented? - I am asking because iterEnd gives me a pointer value and, &iterEnd also gives me a (different) pointer value. Is the random access iterator a pointer within a pointer?
For Random Access Iterator (vector iterator), are the iterators C++
style pointers?
Short answer -- it depends on the compiler.
The internals of a vector iterator is implementation-defined. The std::vector<T>::iterator could have operator - overloaded, thus it gives the illusion of pointer subtraction. Thus if you assume that vector iterators are simple pointers, writing code assuming they are simple pointers will break using various compilers, while for other compilers it will compile successfully.
One such famous case is Visual C++, where in version 6.0, vector iterators were simple pointers, thus many authors at that time using that compiler would write code with the assumption that a std::vector<T>::iterator was just a T*. The code compiled successfully and worked correctly due to the fact that vector iterators were implemented as pointers.
An example would be something like this:
#include <vector>
void foo(char *c)
{
}
int main()
{
std::vector<char> vc;
foo(vc.begin());
}
No compile errors, since vc.begin() was a simple char *.
Then came the subsequent versions of Visual C++, and that code that used to compile successfully under 6.0 is now broken. The std::vector<T>::iterator was no longer a simple T*, but a struct. A lot of code based on the (faulty) reasoning of an iterator being a simple pointer had to be changed for Visual C++ > version 6.0.
I recently started learning about C++ iterators and pointers, and while messing around with some basic exercises I came upon a situation which I think is really unusual.
#include <iostream>
#include <vector>
#include <time.h>
#include <list>
#include <array>
using namespace std;
template<typename ITER>
void print_with_hyphens(ITER begin, ITER end){
cout << "End: " << *(end) << endl;
cout << "Begin: " << *begin << endl;
for(ITER it = begin; it != end; it++){
cout << *it << endl;
}
cout << endl << "Finished" << endl;
}
int main()
{
vector<int> v { 1, 2, 3, 4, 5};
list<int> l { 1, 2, 3, 4, 5};
print_with_hyphens(v.begin(), v.end());
print_with_hyphens(l.begin(), l.end());
// print_with_hyphens(a.begin(), a.end());
return 0;
}
And when I run it like this, I get this unusual result:
Results of the code
Now, the vector is returning a weird (random, if I'm not mistaken) value, because it's trying to access a value that doesn't exist, hence, "past the end" iterator.
And it should be the same for lists, yet, the list is returning the value 5. Shouldn't it also return a "past the end" iterator?
Things such as dereferencing an invalid iterator or accessing an out-of-bounds array index produce undefined behavior.
This means the C++ standard does not specify what should happen if you do it. Anything might happen, such as a segmentation fault, or getting a random value, depending on things like your standard library implementation and compiler.
Needless to say, programs should not rely on undefined behavior.
The phrase "past-the-end" in this context is abstract. It means the iterator is off the end of the logical sequence of elements in the container. It does not mean there is some literal bit of data located just after the container in memory that you can access and read.
Because it's "past-the-end" and doesn't refer to any actual element, dereferencing the end iterator is not permitted. By doing so, you get weird behaviours.
Suppose, I have declared a vector in C++ like this:
vector<int>numbers = {4,5,3,2,5,42};
I can iterate it through the following code:
for (vector<int>::iterator it = numbers.begin(); it!=numbers.end(); it++){
// code goes here
}
Now, I would talk about coding in the block of for loop.
I can access and change any value using this iterator. say, I want to increase every value by 10 and the print. So, the code would be:
*it+=10;
cout << *it << endl;
I can print the address of both iterator and elements that are being iterated.
Address of iterator can be printed by:
cout << &it << endl;
Address of iterated elements can be printed by:
cout << &(*it) << endl;
But why the iterator itself could not printed by doing the following?
cout << it <<endl;
At first I thought the convention came from JAVA considering the security purpose. But if it is, then why I could print it's address?
However, Is there any other way to do this? If not, why?
Yes, there is a way to do it!
You can't print the iterator because it is not defined to have a value.
But you can perform arithematic operations on them and that helps you to print the value (of the iterator).
Do the following.
cout << it - v.begin();
Example:
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;
int main () {
vector<int> v = {20,3,98,34,20,11,101,201};
sort (v.begin(), v.end());
vector<int>::iterator low,up;
low = lower_bound (v.begin(), v.end(), 20);
up = upper_bound (v.begin(), v.end(), 20);
std::cout << "lower_bound at position " << (low - v.begin()) << std::endl;
std::cout << "upper_bound at position " << (up - v.begin()) << std::endl;
return 0;
}
Output of the above code:
lower_bound at position 2
upper_bound at position 4
Note: this is just a way to get things done and no way I have claimed that we can print the iterator.
...
There is no predefined output operator for the standard iterators because there is no conventional meaning of printing an iterator. What would you expect such an operation to print? While you seem to expect to see the address of the object the iterator refers to, I find that not clear at all.
There is no universal answer to that, so the committee decided not to add a those operators. (The last half sentence is a guess, I am not part of the committee.)
If you want to print those iterators, I would define a function like print(Iterator); (or something like this, whatever fits your needs) that does what you want. I would not add an operator << for iterators for the reason I mentioned above.
why the iterator itself could not printed by doing the following?
Because, it is not defined to a value internally.
Is there any other way to do this?
Basically, the compiler does not facilitate it by default, you may try to edit the compiler code! But it is too terrific you know!
If not, why?
Because it has no well-defined way to express it.
You can't print the iterator because it is not defined to have a value. But you can perform arithematic operations on them and that helps you to print the value (of the iterator).
I have a vector storing {1,2,3,4,5}. I tried to print *(vec.end()) and got back the result 6. I don't know how to explain this. Similarly, calling vec.find(500) gave the result 6. Why am I getting this number?
#include<iostream>
#include<iterator>
#include<set>
#include<map>
int main()
{
int a[] = {1,2,3,4,5};
std::set<int> set1(a,a+sizeof(a)/sizeof(int));
for (std::set<int>::iterator itr=set1.begin();itr!=set1.end();++itr){
std::cout << *itr << std::endl;
}
//std::pair<std::set<int>::iterator, bool> ret;
//ret = set1.insert(1);
//std::cout << *(ret.first) << "first;second" << ret.second << std::endl;
std::set<int>::iterator itr1 = set1.begin();
set1.insert(itr1,100);
std::advance(itr1,3);
std::cout << *itr1 << std::endl;
std::cout << *(set1.find(500)) << std::endl;
std::cout << *(set1.end()) << std::endl;
}
This line invokes undefined behavior:
std::cout << *(set1.end()) << std::endl;
It is undefined behavior to dereference the end() iterator. Thus anything can be expected.
In C++ containers, the end iterator gives an iterator one past the end of the elements of the container. It's not safe to dereference the iterator because it's not actually looking at an element. You get undefined behavior if you try to do this - it might print something sensible, but it might just immediately crash the program.
Hope this helps!
Never try to use end() of any stl container because it does not point to a valid data. It always point to a chunk of memory that is located after the actual data. Use end() only to check whether your iterator has come to end or not. This image clearly explains where end() is located in default (non-reversed) range:
vec.end() does not point to the last element, but somewhat "behind" the last one.
You are not accessing the last element in the vector. Instead you are dereferencing an "invalid" iterator, which is undefined behaviour and turns out to be an invalid index in the vector in this case.
vec.find returns the end iterator if the searched element can not be found.
I have a map defined like this
std::map<some_key_type, std::string::iterator> mIteratorMap;
And a huge string named "mHugeString". Then I walk trough the string collecting iterators like this:
std::string::iterator It=mHugeString.begin();
std::string::iterator EndIt=mHugeString.end();
for(;It!=EndIt;++It){
...defining a key element...
if(need_to_store_an_iterator)mIteratorMap[key_of_a_right_type]=It;
}
In the end I should recieve a map, where an iterator is associated with a some sort of key. But the iterator somehow looses itself when being paired with a key by "make_pair", unless it points to a place somewhere in the end of a string. It's hard to tell, but maybe last 256 bytes are fine.
So the question is not how to avoid loosing iterators, it was a stupid idea to store them anyways, but why trying to store an iterator in the begining of the string fails, and why the same with the iterators on the end works fine? What is the difference between them?
I haven't tried it but I would have expected that, of course you can store iterator values as values in a map.
Do you know that if you change the contents of mHugeString then any iterators into it which you have previously stored are now invalid?
You might choose to store the index into the string, instead of the iterator.
I am not sure why it should be problem. I wrote this code to check storage and retrieval of iterator which seems to work fine. [Note: I am not using make_pair as it should not be relevant, give try without using it though!]
#include <string>
#include <iostream>
#include <map>
enum UniqueKey {One, Two, Three};
typedef std::map<UniqueKey, std::string::iterator> UniqueKeyStringMap;
int main()
{
UniqueKeyStringMap storage;
std::string stringOne = "This is one string";
std::string::iterator it = stringOne.begin() + 8; // "o"
std::cout << " Iterator to store: " << std::string(it, it + 3) << std::endl;
storage[UniqueKey::One] = it; // Store iterator
// Retrieve and print, string and map are valid
UniqueKeyStringMap::iterator mapIter = storage.find(UniqueKey::One);
if (mapIter != storage.end())
{
std::cout << " From storage: " <<
std::string(mapIter->second, mapIter->second + 3) << std::endl;
}
}
expected output:
Iterator to store: one
From storage: one
It's fine, you can store iterators in the map. If you get some error, that is caused by something else. Note that if you modify your string, iterators pointing into your string will become invalid.
Please show us a complete, compilable code snippet that is rendered unusable, so we can analyze it.