Re: STL map question : directed to stl map expert(s)....
altagrego ha scritto:
Given the following:
// map construction:
map<string, CMyClass*> myMap;
// construct next map key/element
CMyClass* pMC = new CMyClass("MyDataMember");
string myString = "mystring";
// insert key/element into map;
myMap[myString ] = pMC;
Think about it: what would happen if the map already contains the key
"mystring"? The old pointer stored in myMap["mystring"] gets overwritten
with the new value contained in pMC. Unfortunately, the old pointer was
THE custodial pointer for an object created with new and you now face a
memory leak!
You have two choices:
1) use a shared_ptr as the value, as in:
map<string, boost::shared_ptr<CMyClass> > myMap;
// init pMC and myString as above
myMap[myString].reset(pMC);
2) check for the existence of key before inserting:
map<string, CMyClass*>::iterator it = myMap.find(myString);
if (it == myMap.end)
{
// ok, it's safe to insert
myMap[myString] = new CMyClass("MyDataMember");
}
else
{
// key already present in map
}
this code can be optimized by using equal_range() and insert() instead
of find() and operator[] (left as exercise for the reader).
QUESTION:
after accessing an element via a key..
In addition to removing an element from the map using "erase()", do I
still need to call delete on the "removed" object itself explicitly..
my access/erase/delete example ??????
CMyClass* p = myMap[myString];
myMap.erase(myString)
delete p;
Yes, you can do so, although it's not very efficient, because:
1) in all cases, the code performs a search for the key myString twice:
once when calling operator[] and once when calling erase()
2) if myString is not present as a key, you end up adding a new element
to the map and then immediately removing it. Fortunately, the extra call
to delete p will be a no-op because p will be NULL
3) operator[] can be inefficient anyway, because it may need to perform
one unneeded copy of the string myString
A better solution is the following:
map<string, CMyClass*>::iterator it = myMap.find(myString);
if (it != myMap.end)
{
CMyClass* p = it->second;
myMap.erase(it);
delete p;
}
(if you are wondering, the apparently identical code:
delete it->second;
myMap.erase(it);
invokes undefined behaviour, because deleting the pointer makes the
pointer uncopiable, thus you would be violating the container pre-condition)
Notice that if you choose the approach with the shared_ptrs the code
would simply be:
myMap.erase(myString);
because the destructor of the shared_ptr will take care of deleting the
object. Another good reason to prefer shared_ptr.
HTH,
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]