-
STL map problem
What's wrong with this code? It seems to work fine most of the time, but I'm getting EXC_BAD_ACCESS on some occasions.
Here is the debug stack:
Code:
#4 0x00018016 in std::map<std::string, Item*, std::less<std::string>, std::allocator<std::pair<std::string const, Item*> > >::find at stl_map.h:542
#3 0x00017f51 in std::_Rb_tree<std::string, std::pair<std::string const, Item*>, std::_Select1st<std::pair<std::string const, Item*> >, std::less<std::string>, std::allocator<std::pair<std::string const, Item*> > >::find at stl_tree.h:1378
#2 0x00017efe in std::less<std::string>::operator() at stl_function.h:227
#1 0x00002fff in std::operator< <char, std::char_traits<char>, std::allocator<char> > at basic_string.h:2228
#0 0x97dab336 in std::string::compare
Why would this crash on string compare? I've tried several variations on the format of the string being passed to find(), but can't get any of them to work.
Thanks so much for your help!
Code:
// Group.h
#include "Item.h"
typedef map<string, Item*> GroupMap;
class Group {
public:
Group();
void addItem(string name, Item* item);
Item* getItem(string name);
protected:
GroupMap items;
};
// Group.cpp
#include "Group.h"
Group::Group() {}
void Group::addItem(string name, Item* item) {
items.insert(pair<string,Item*>(name.data(),item));
}
Item* Group::getItem(string name){
GroupMap::iterator it;
it=items.find(name.data());
if(it != items.end()) {
return (*it).second;
}
return NULL;
}
-
If I had to guess...
Code:
Item* Group::getItem(string name){
GroupMap::iterator it;
it=items.find(name.data());
if(it != items.end()) {
return (*it).second;
}
return NULL;
}
The data member function does not return a valid C style string... what it returns does not have a null terminator. I'm guessing this causes a problem when doing the find. Since the first member of the map is a std::string, there should be no problem using find with the std::string variable name directly.
Code:
it=items.find(name);
-
Hey,
Thanks.
Unfortunately, that isn't the problem. I also tried find(name) and got the same results.
-
This:
Code:
return (*it).second;
Usually looks better as:
Also, this:
Code:
void Group::addItem(string name, Item* item) {
items.insert(pair<string,Item*>(name.data(),item));
}
Has the same problem I mentioned in the earlier post.
...it's been awhile since I've used maps. That may or may not be a source of your problems in debugging.
[edit]Post the newest code you've got once you've made the changes.[/edit]
-
Did you fix it in items.insert() as well? I'm a bit confused as to why your backtrace doesn't go down into your actual code.
-
Hi,
Thanks for your help. Here is the modified code. Still produces the same problem.
Code:
// Group.h
#include "Item.h"
typedef map<string, Item*> GroupMap;
class Group {
public:
Group();
void addItem(string name, Item* item);
Item* getItem(string name);
protected:
GroupMap items;
};
// Group.cpp
#include "Group.h"
Group::Group() {}
void Group::addItem(string name, Item* item) {
items.insert(pair<string,Item*>(name,item));
}
Item* Group::getItem(string name){
GroupMap::iterator it;
it=items.find(name);
if(it != items.end()) {
return it->second;
}
return NULL;
}
-
Are you using gdb? Can you go up (as many times as necessary) until you get to your code? That would give you information like (1) what line we're on in your code (2) what the values of the variables like name and item and things are.
-
Hey,
Sorry, here is a more complete backtrace:
Code:
#6 0x00012085 in GroupController::getInfo at GroupController.cpp:128
NOTE: here is what the calling method looks like...
void GroupController::getInfo() {
Item* myItem = theGroup->getItem("Info");
// ... nothing else in this function relates to the problem...
}
#5 0x000176f3 in Group::getItem at Group.cpp:22
NOTE: Group.cpp:22 is "it=items.find(name);"
#4 0x00018016 in std::map<std::string, Item*, std::less<std::string>, std::allocator<std::pair<std::string const, Item*> > >::find at stl_map.h:542
#3 0x00017f51 in std::_Rb_tree<std::string, std::pair<std::string const, Item*>, std::_Select1st<std::pair<std::string const, Item*> >, std::less<std::string>, std::allocator<std::pair<std::string const, Item*> > >::find at stl_tree.h:1378
#2 0x00017efe in std::less<std::string>::operator() at stl_function.h:227
#1 0x00002fff in std::operator< <char, std::char_traits<char>, std::allocator<char> > at basic_string.h:2228
#0 0x97dab336 in std::string::compare
thanks again. weird problem... can't make sense of it.
-
There is no problem in the last code snippet you posted so the problem is elsewhere.
Please try and make a minimal but complete compileable example program that produces the problem.
-
Are you perhaps accessing a NULL pointer in your GroupController::getInfo method returned from that call to getItem? Do you have guards against that?
-
Thanks again for your help.
I believe the problem has to do with the string I'm passing to find() in the method getItem().
Within my program, getItem() is often evoked during a callback event. It's only in these cases that the find function crashes. I have the suspicion that the string can't be accessed properly during the event callback because the string is already being accessed from somewhere else? I'm not doing any threading, but is it possible that my callback events could cause similar problems to thread accessing of strings? Is there any way I can test this? Would making some sort of copy of the string help at all? Sorry for my confusion... can't make head or tail of this problem.
-
You're passing the string by copy anyway. Again, if you type "up" five times (assuming you're running this in GDB, or are attaching GDB to it), you can see exactly what name and all your other variables are (by doing "print name" or "print Item" etc.). So do that, and you'll know whether you're getting passed garbage or what.
-
If you are not using threading then nothing else is accessing the string at the same time this method is. I would prefer to pass the string via const reference. I highly doubt the string is the problem as I've used this same type of map thousands of times with no trouble. I suspect some object is using the map and not checking if the get returns null. It would be wise to allow the add function to return a boolean. Insert returns a pair<iterator,bool>. The iterator is the insertion point and the bool indicates if the operation was successful or not.
-
Oh, thanks.
Here is what print name gives back:
Code:
// WITHOUT CALLBACK EVENT
$1 = {
static npos = 4294967295,
_M_dataplus = {
<std::allocator<char>> = {
<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
members of std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Alloc_hider:
_M_p = 0x1b0d05c "a"
}
}
// WITH CALLBACK EVENT
$1 = {
static npos = 4294967295,
_M_dataplus = {
<std::allocator<char>> = {
<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
members of std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Alloc_hider:
_M_p = 0x342174a9 <Address 0x342174a9 out of bounds>
}
}
How can I fix this?
-
If this came from a callback, then up one more level on your call stack had better be, therefore, the function where the callback is happening. Go there, and look around, and see why it's passing basically a bad string to you.