Why can't I put an iterator in map? - c++

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.

Related

What is the meaning of .end()->first in maps

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.

How to find the value for a key in unordered map?

I am trying to do the below sample in unordered map in c++
my_dict = {'one': ['alpha','gamma'], 'two': ['beta'], 'three' : ['charlie']}
print(my_dict["one"]) // ['alpha','gamma']
I tried using find operator like below
int main ()
{
std::unordered_map<std::string, std::vector<std::string>> dict;
dict["one"].push_back("alpha");
dict["one"].push_back("beta");
dict["two"].push_back("gamma");
auto it = dict.find("one");
cout<<it->second<<endl; // expected output alphabeta
return 0;
}
But I am not able to retrieve the value for this key dict["one"]. Am i missing anything ?
Any help is highly appreciated.
Thanks
The failure you are encountering is due to it->second being a std::vector object, which cannot be printed to std::cout because it lacks an overload for operator<<(std::ostream&,...).
Unlike languages like Python that do this for you, in C++ you must manually loop through the elements and print each entry.
To fix this, you will need to change this line:
cout<<it->second<<endl; // expected output alphabeta
To instead print each object in the container. This could be something simple like looping through all elements and printing them:
for (const auto& v : it->second) {
std::cout << v << ' '; // Note: this will leave an extra space at the end
}
std::cout << std::endl;
Or you can go more complex if the exact formatting is important.
#DanielLangr posted a link in the comments to the question that summarizes all possible ways of doing this, and I recommend taking a look if you're wanting anything more complex: How do I print the contents to a Vector?
This is because your it->first will point to the key of the dictionary i.e. "One" and it->second will point to the value i.e. the vector.
So to print elements of the vector you need to specify the indexes of the vector that you are printing as well. The following code will give you the result you want:
int main() {
std::unordered_map <std::string, std::vector<std::string>> dict;
dict["one"].push_back("alpha");
dict["one"].push_back("beta");
dict["two"].push_back("gamma");
auto it = dict.find("one");
cout<<it->second[0]<<it->second[1]<<endl; // expected output alphabeta
return 0;
}
P.S. Please accept my answer if you find it useful as that would help me get some reputation points

how the iterator in c++ could be printed?

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).

C++ - Accessing member functions from a map of object pointers, in a seperate class via getter functions

I'm fairly new to C++, I've tried to figure this out on my own but can't quite get there.
I've defined a map of pointers to a group of dynamically allocated objects in one class, with strings as the keys, along with two iterators (begin() and end()), and two getter functions corresponding to each iterator.
class a{
std::map<string, Fruit*> fruitSalad;
std::map<string, Fruit*>::iterator begin = fruitSalad.begin(), end = fruitSalad.end();
std::map<string, Fruit*>::iterator getBeginIter() const;
std::map<string, Fruit*>::iterator getEndIter() const;
};
the objects referenced in the map, and their member functions need to be accessible in a separate driver class. To test my implementation I've been trying to print values from the objects with a for loop, by accessing the iterators via their accessors, as shown in the code below.
#include "a.h"
int main(){
A fruitBowl;
std::map<string, Object*>::iterator iter;
for(iter = fruitBowl.getBeginIter(); iter != fruitBowl.getEndIter(); iter++){
cout << iter.getName() << " " << iter.getQuantity() << endl;
}
}
But I am getting the following error
error: 'std::map<std::basic_string<char>, Fruit*>:: iterator' has no member named getName()
error: 'std::map<std::basic_string<char>, Fruit*>:: iterator' has no member named getQuantity()
I assume I'm doing something wrong with the assignment of the iterators in my driver class, but what exactly am I doing wrong?
First, when you write iter = fruitBowl.getBeginIter();, iter is an iterator. This is a pointer-like object. If you want to access the method of the pointed-to object, you must first dereference it.
Second, the objects contained in the std::map<foo, bar> are std::pairs of foo, bar.
So the usage looks like
for(iter = fruitBowl.getBeginIter(); iter != fruitBowl.getEndIter(); iter++){
auto pFruit = (*iter).second;
cout << (*pFruit).getName() << " "
<< (*pFruit).getQuantity() << endl;
}
The first dereference is to access the value of the key-value pair in the map;
the second one is to access the Fruit referenced by the pointer.
Or, using the syntactic sugar for pointer manipulation:
for(iter = fruitBowl.getBeginIter(); iter != fruitBowl.getEndIter(); iter++){
auto pFruit = iter->second;
cout << pFruit->getName() << " "
<< pFruit->getQuantity() << endl;
}
Thanks for the responses guys, I appreciate your help.
Turns out it was a relatively simple problem and fix as most beginner programming errors are. I misinterpreted Joachim Pileborg's comment earlier in the thread- I was in fact using begin() and end() to start with, although this comment did set me on the right line of thinking.
The problem was that although I initialized the the iterators that I named 'begin' and 'end' with the iterators returned from the iterator funcitons begin() and end(), I was doing so immediately after I defined the map, before it had any values in it- as shown below.
std::map<string, Fruit*> fruitSalad;
std::map<string, Fruit*>::iterator begin = fruitSalad.begin(), end = fruitSalad.end();
So i guess this meant my iterators both pointed to the same memory location, so when I accessed these iterators via the getters in the driver class, the for loop would terminate just as soon as it would begin which is why no values were being printed even after fixing the original errors in my code as pointed out by mookid.
To remedy this I simply initialised the values of the pointers in class a inside the constructor, which is where the values of the map are read in from a file as shown below.
// class a constructor
a(){
... // initialise some other variables
loadFruitValues(); // reads values in from a .txt file to the map
iter1 = fruitSalad.begin();
iter2 = fruitSalad.end();
}
Now when the code runs the iterators returned correctly point to the beginning and end of the map, allowing the for loop to iterate over the contents stored inside the map.
Thanks again for the replies, I'd still be stuck without all of your input. Both answers helped me equally but I think I can only site one as being the one that helped me the most. And my apologies for my original question not being formatted correctly, it's my first post- I'll try to make sure my next ones on point.

What's this unexpected std::vector behavior?

I found something surprising with std::vector that I thought I'd ask about here to hopefully get some interesting answers.
The code below simply copies a string into a char vector and prints the contents of the vector in two ways.
#include <vector>
#include <string>
#include <iostream>
int main()
{
std::string s("some string");
std::vector<char> v;
v.reserve(s.size()+1);
// copy using index operator
for (std::size_t i=0; i<=s.size(); ++i)
v[i] = s[i];
std::cout << "&v[0]: " << &v[0] << "\n";
std::cout << "begin/end: " << std::string(v.begin(), v.end()) << "\n";
// copy using push_back
for (std::size_t i=0; i<=s.size(); ++i)
v.push_back(s[i]);
std::cout << "&v[0]: " << &v[0] << "\n";
std::cout << "begin/end: " << std::string(v.begin(), v.end()) << "\n";
return 0;
}
Building and running this yields:
$ g++ main.cpp -o v && ./v
&v[0]: some string
begin/end:
&v[0]: some string
begin/end: some string
My expectation was that it would print the string correctly in both cases, but assigning character by character using the index operator doesn't print anything when later using begin() and end() iterators.
Why isn't end() updated when when using []? If this is intentional, what's the reason it's working like this?
Is there a reasonable explanation for this behaviour? :)
I've only tried this with gcc 4.6.1 so far.
Typical example of Undefined Behavior.
You are only ever allowed to access elements by index (using operator[]) between 0 and v.size()-1 (included).
Using reserve does not modify the size, only the capacity. Would you have used resize instead, it would work as expected.
In the first case, you have undefined behaviour. reserve sets the capacity, but leaves the size as zero. Your loop then writes to invalid locations beyond the end of the vector. Printing using the (invalid) pointer appears to work (although there is no guarantee of that), since you've written the string to the memory that it points at; printing using the iterator range prints nothing, because the vector is still empty.
The second loop correctly increases the size each time, so that the vector actually contains the expected contents.
Why isn't end() updated when when using []? If this is intentional, what's the reason it's working like this?
[] is intended to be as fast as possible, so it does no range checking. If you want a range check, use at(), which will throw an exception on an out-of-range access. If you want to resize the array, you have to do it yourself.