Reputation: 96141
Consider the following program, which is a minimal example trying to reproduce a problem with some legacy code:
#include <iostream>
#include <ext/hash_map>
// Define a hash for std::string class so we can use it as keys
// in hash_map below.
namespace __gnu_cxx {
template <>
struct hash<std::string> {
size_t operator() (const std::string& x) const {
return hash<const char*>()(x.c_str());
}
};
}
// Data class contains a string
class Data {
public:
std::string s;
Data() { s = "foobar"; }
Data(std::string s_) : s(s_) {}
};
// Map keyed by string. Values are Data instances
typedef __gnu_cxx::hash_map<std::string, Data> DataMap;
int main()
{
DataMap m;
std::string key = "test";
// I am storing a "Data" instance d, for "key". d.s is the same as key.
Data d = Data(key);
m[key] = d;
DataMap::iterator it = m.find(key);
if (it == m.end()) {
std::cerr << "not there " << std::endl;
return 1;
}
Data *dp = &it->second;
// Question about the following line. Is the behavior well-defined?
m.erase(dp->s);
return 0;
}
I am storing my class Data
instances in a hash_map
. I search for a particular data member using a key
, and then erase that value using m.erase(dp->s)
. m.erase(dp->s)
will delete the object pointed to by dp
. Am I allowed to use dp->s
in the call to erase()
, or must I first make a copy and then erase()
:
std::string key_to_delete = dp->s;
m.erase(key_to_delete);
Upvotes: 1
Views: 1734
Reputation: 12397
Looking at the implementation, it seems as if even after the node (the pair pointed to by it
) is deleted, the key passed to the erase
function is still referenced. If dp
is deleted, then the reference to dp->s
becomes invalid. Yet the implementation of hash_map
is still trying to dereference it. Fail.
You would need to pass something that is guaranteed to stay valid for the call to erase
.
You could
m.erase(key);
Or you can use the iterator returned by find
to do the erase:
m.erase(it);
Upvotes: 1