Reputation: 1450
I encountered this kind of issue: a possible memory leak.
Imagine if you store two different heap pointers for same key.
#include <map>
std::map<int, int*> myMap;
void Store(int key, int* value)
{
myMap[key] = value;
}
int main()
{
Store(42, new int(42));
Store(35, new int(35));
delete myMap[42];
delete myMap[35];
}
I thought about fixing that way:
#include <map>
std::map<int, int*> myMap;
void Store(int key, int* value)
{
auto it = myMap.find(key);
if (it != myMap.end()))
{
delete it->second;
it->second = value;
}
else
{
myMap[key] = value;
}
}
int main()
{
Store(42, new int(42));
Store(35, new int(35));
delete myMap[42];
delete myMap[35];
}
But there are two logarithmic look-ups instead of one now...
Then I thought about this following code,
#include <map>
std::map<int, int*> myMap;
void Store(int key, int* value)
{
auto& mappedValue = myMap[key];
if (mappedValue == nullptr)
{
mappedValue = value;
}
else
{
delete mappedValue;
mappedValue = value;
}
}
int main()
{
Store(42, new int(42));
Store(35, new int(35));
delete myMap[42];
delete myMap[35];
}
but how can I be certain mappedValue will always point to nullptr if there is no associated value ?
What would you suggest to tackle memory leak and stick with logarithmic complexity ?
EDIT: refactoring is very costy, I'm looking for a solution without smart pointers.
Upvotes: 0
Views: 1235
Reputation: 1245
why not using map::insert
auto res = myMap.insert(std::make_pair(key,value));
if ( ! res.second ) {
delete res.first->second;
res.first->second = value;
}
Upvotes: 1
Reputation: 41750
With the new standard c++11, std::unique_ptr
is your friend. It has no overhead whatsoever, and provides memory safety:
std::map<int, std::unique_ptr<int>> myMap;
void Store(int key, int* value)
{
myMap[key] = std::unique_ptr<int>{value};
}
int main()
{
Store(42, new int(42));
Store(35, new int(35));
}
No memory leak with that. If you have access to c++14, you could even do this:
std::map<int, std::unique_ptr<int>> myMap;
void Store(int key, std::unique_ptr<int> value)
{
myMap[key] = std::move(value);
}
int main()
{
Store(42, std::make_unique<int>(42));
Store(35, std::make_unique<int>(35));
}
No new, no delete. No memory leak and safe.
Upvotes: 1
Reputation: 3142
but how can I be certain mappedValue will always point to nullptr if there is no associated value ?
If operator[]
adds a new element it is value-initialized. For non-class types as pointers are this is equivalent to zero-initialization which in turn is a nullptr
in case of pointers. See std::map::operator[]
.
Upvotes: 3
Reputation: 76297
You might consider using the RAII in the form of smart pointers, and instead define your map as
#include <map>
#include <memory>
std::map<int, std::shared_ptr<int>> myMap;
(For this to work make sure to configure your compiler to c++11 mode.)
Your map becomes something like: map integers to a pointer-like object that will take care of deallocation.
Upvotes: 2