map: Bad Ptr even if the key was found - c++

I have a map inside struct:
struct amountOfDist
{
int time;
vector<int> distVector;
map<string,int> pairsMap;
};
amountOfDist m_tempDistStruct;
when the code runs, it crushes when I try to find a value:
if(m_tempDistStruct.pairsMap.find("(1,2)")->second != 1)
{
...
}
I tried to isolate the command by:
map<string,int>::iterator it;
it = m_tempDistStruct.pairsMap.find("(1,2)");
and I get padptr. But when I put break point on the line:
it = m_tempDistStruct.pairsMap.find("(1,2)");
I can see that the map hols all the keys and values (the correct ones) and the key (1,2) exists.
Why does the find command returns badptr?
I will be happy for guidance.
Thanks.

If the map really does contain the key you're looking for, then your code should work; something else has gone horribly wrong if it doesn't. However, the code is rather fragile, since it will give undefined behaviour if the key is missing.
You have to check whether find succeeded before dereferencing it; if it fails, then it returns a past-the-end iterator which isn't dereferencable. Alternatively, use [] which will insert a new element if it was missing.
So safer versions are:
// use find and check it exists
auto found = map.find(key);
if (found != map.end() && found->second != 1)
// use [] to insert if it doesn't exist
if (map[key] != 1)
If neither of these work, or you're absolutely sure that the key must exist, then we'll need to see a complete test case to figure out what's going wrong with the code you haven't shown us.

Using your code, I get totally correct behavior. So I am pretty sure that the value you're looking for is not in the map.
amountOfDist m_tempDistStruct;
m_tempDistStruct.pairsMap["(1,2)"] = 10;
if (m_tempDistStruct.pairsMap.find("(1,2)")->second == 10)
{
cout << "GOT HERE!" << endl;
}
The above code snippet adds "(1,2)" => 10 to the map, then finds it just fine. I suspect the key in your map is subtly different to what you think it is.

Related

modify value of key in boost unordered_map

I have a boost::unordered_map which I want to modify the value of a particular key.
I have seen the question here.
what makes my question different is that in my map key is a simple int and my value is std::vector. I want to update this value by inserting a new PoitCoord at the second position of the vector.
One solution is like that:
auto it = map.find(key);
if(it != map.end())
{
std::vector<PointCoord> pntcrds = it->second;
pntcrds.insert((pntcrds.begin()+1), new_value);
it->second = pntcrds;
}
I am wondering if there is less verbose solution.
The map does not have anything to do with your insertion, if I understand your question correctly. You are only modifying a vector which happens to be stored in a map. You are not modifying the key of a map, but one of it's values.
So the short solution would be:
auto it = map.find(key);
if(it != map.end() && !it->second.empty() )
{
it->second.insert( (pntcrds.begin()+1), new_value);
}
If you know that the key exists in your map, you can shorten this to:
std::vector<PointCords> & pntCords = map[key];
if( ! pntCords.empty() )
pntCords.insert( pntCords.begin()+1, new_value );
NB: If you use the second method and the key does not yet exist, a default constructed (=empty) std::vector<PointCords> will be inserted into the map.
You have to find the key iteration position then update directly the found key by
it->second.insert( (pntcrds.begin()+1), new_value);
but you have to be sure that you've found the iteration and as #Johannes said your vector is not empty.
There is indeed a very simple solution, that covers all the scenarios you might think about. And it is
myMap[key].insert(pntcrds.begin()+1);
If the key does not exist, it will be inserted. otherwise, the value will be updated to the new one;
But you must make sure you have at least one element in your vector. Otherwise, it will crash.
A similar trick would be
myMap[key].push_back(new_value); // appends to the end of the vector

Can I get a value from std::map without crashing if the key doesn't exist?

I have C++ code like this:
if(rtstructure.find(varName) != rtstructure.end()) {
rtdef = rtstructure[varName];
}
where rtstructure is std::map with std::string for the key.
This code works but it seems like a waste to make it search twice for the same key. If I omit the if case around the assignment, the program crashes if varName points to a key that doesn't exist.
Can I in a single map operation look up a key in a std::map and get its value if it exists, without crashing if it doesn't exist?
find give you a std::map<>::iterator that holds/point to std::pair<>. The iterator can be saved and reused (given that you did not do anything to invalidate it such as erase).
// i don't know the type of rtstructure so i use auto
// you can replace it to the correct type if C++11 is not available
auto it = rtstructure.find(varName);
if(it != rtstructure.end()) {
rtdef = it->second;
}

c++: use map as value of another map

I just wonder if I can use a "complicated" map as the value of another map. I have self-defined several structs as follow:
typedef std::vector<std::string> pattern;
typedef std::map<int, std::vector<pattern>> dimPatternsMap;
typedef std::map<int, dimPatternsMap> supportDimMapMap;
OK let me explain these things...pattern is a vector of strings. For the "smaller" map dimPatternsMap, the key is an integer which is the dimension of pattern (the size of that vector containing strings) and the value is vector containing patterns (which is a vector of vectors...).
The "bigger" map supportDimMapMap also use an integer as the key value, but use dimPatternsMap as its value. The key means "support count".
Now I begin to construct this "complicated" map:
supportDimMapMap currReverseMap;
pattern p = getItFromSomePlace(); //I just omit the process I got pattern and its support
int support = getItFromSomePlaceToo();
if(currReverseMap.find(support) == currReverseMap.end()) {
dimPatternsMap newDpm;
std::vector<pattern> newPatterns;
newPatterns.push_back(currPattern);
newDpm[dim] = newPatterns;
currReverseMap[support] = newDpm;
} else{
dimPatternsMap currDpm = currReverseMap[support];
if(currDpm.find(dim) == currDpm.end()) {
std::vector<pattern> currDimPatterns;
currDimPatterns.push_back(currPattern);
currDpm[dim] = currDimPatterns;
} else {
currDpm[dim].push_back(currPattern);
}
}
Forgive me the code is really a mass...
But then as I want to traverse the map like:
for(supportDimMapMap::iterator iter = currReverseMap.begin(); iter != currReverseMap.end(); ++iter) {
int support = iter->first;
dimPatternsMap dpm = iter->second;
for(dimPatternsMap::iterator ittt = dpm.begin(); ittt != dpm.end(); ++ittt) {
int dim = ittt->first;
std::vector<pattern> patterns = ittt->second;
int s = patterns.size();
}
}
I found the value s is always 1, which means that for each unique support value and for each dimension of that support value, there is only one pattern! But as I debug my code in the map constructing process, I indeed found that the size is not 1 - I actually added the new patterns into the map successfully...But when it comes to traversing, all the sizes become 1 and I don't know why...
Any suggestions or explanations will be greatly appreciated! Thanks!!
dimPatternsMap currDpm = currReverseMap[support];
currDpm is a copy of currReverseMap[support]. It is not the same object. So then when you make changes to currDpm, nothing within currReverseMap changes.
On the other hand, if you use a reference:
dimPatternsMap& currDpm = currReverseMap[support];
then currDpm and currReverseMap[support] really are the same object, so later statements using currDpm will really be changing a value within currReverseMap.
There are a few other places where your code could benefit from references too.
My guess: you should use a reference in your else:
dimPatternsMap& currDpm = currReverseMap[support];
Your current code creates a copy instead of using the original map.
Your problem is this line:
dimPatternsMap currDpm = currReverseMap[support];
Based on the code following it, it wants to read like this:
dimPatternsMap& currDpm = currReverseMap[support];
Without the & you modify a copy of the entry rather than the existing entry.
Your code is making several copies of the objects underneath, try using more references and iterators (find() already gives you an element if it was found, for example).
For example, dimPatternsMap currDpm = currReverseMap[support]; actually makes a copy of a map in your structure and adds an element to it (not to the original). Try using a reference instead.

Vector gets iterated more times than size()

I've got this piece of code:
for (std::vector<Marker>::iterator it = markers.begin(); it != markers.end(); ++it) {
if (it->getDots().size() < 3) {
markers.erase(it);
}
}
In one of test inputs (the app does image analysis) I get a segfault. I tried to debug the code (to no avail) and noticed one thing. When asking gdb to p markers.size() i receive $9 = 3. So I would expect the loop to iterate three times, but surprisingly it does it (at least) 5 times. In fifth iteration there's a segfault. What I also noticed is that it's not the dereference of *it (here it->) that causes the error. It's specifically it->getDots(), which is a simple getter.
I write in C++ very rarely, so it might be some simple mistake, but neither my debugging, nor googling brought any solution. Could you help?
I'd like to emphasize, that on various different inputs (slightly different images) this function works properly, so it's even harder for me to trace the bug down.
vector::erase invalidates all iterators pointing to the element being erased, and all elements that follow. So it becomes invalid, and ++it expression on the next loop iteration exhibits undefined behavior.
The best way to code this logic is with erase-remove idiom.
The problem is this line:
markers.erase(it);
The iterator is invalidated. But that's okay, erase returns a valid iterator:
auto it = markers.begin();
while(it != markers.end())
{
if(it->getDots().size() < 3) {
it = markers.erase(it);
}
else ++it;
}
You need to update it when you erase:
it = markers.erase(it);
since erase will "change" the vector, and your current it is no longer valid (and only do it++ if when you didn't erase it).
However, the more common way to do this is to use this type of construction:
markers.erase(std::remove(markers.begin(), markers.end(), number_in), markers.end());

Question about C++ Iterator `map`

In below codes,
std::map<Key,Int>::iterator p;
p = randomTable[chunk].find(value);
if (p != randomTable[chunk].end()) {
} else {
}
How does the p != randomTable[chunk].end() works?
Does this mean, for all elements in randomTable that is not the last (end()) element?
find(value) will return the same as end() if value is not in the map. So if value is in the map, you'll go into the "if" branch, and if not, you'll go into the "else" branch.
end() isn't actually a member of the map - it points to the "element after the end". This is a slightly odd idea, but it probably helps to think that the search has looked at all of the elements in the map and failed to find the one you're looking for.
No. In the documentation for std::map<K, V>::find, you can see:
Return Value
An iterator to the element, if the specified key value is found, or map::end if the specified key is not found in the container.
So, that if statement is just checking that you actually found something.