In the following scenario, is 'T' properly freed? or will an increasing amount of 'loads' cause a memory leak?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
typedef boost::ptr_map<std::string, T> map_t;
typedeftemplate map_t::iterator map_i;
T* Get(std::string key)
{
map_i i = m_map.find(key); //m_map declared elsewhere
if(i != m_map.end())
return i->second; //return if exists
T *p = new T; //otherwise create
Load(key, p); //function that populates p with meaningful information
m_map[key] = *p;
return p;
}
void Free(std::string key)
{
m_map.erase(key); //will this free memory populated by the mapped value?
}
In this particular case, T is an SDL_Surface. I'm attempting to manage all of the images I've loaded so that I don't load anything into memory more than once.
no, this line: m_map[key] = *p;
allocates a new managed pointer inside the map and copies your value over, leaking your original allocation.
use m_map.insert(key, p);
Also, doesn't SDL_Surface need more than just a delete p? You may be better off with a regular map holding unique_ptr with a custom deleter that calls SDL_FreeSurface(). (it's possible to provide custom deleters to boost pointer containers, but it's not as simple, as far as I can see)
template<class T>
class ResourceManager
{
public:
T *Get(std::string key);
void Free(std::string key)
{
map_i i = m_map.find(key)
if(i == m_map.end())
return;
OnFreeResource(i->second);
m_map.erase(i);
}
protected:
virtualvoid OnLoadResource(std::string key);
virtualvoid OnFreeResource(T *t);
private:
map_t m_map;
};
class SurfaceManager : public ResourceManager<SDL_Surface>
{
protected:
OnLoadResource(std::string key, SDL_Surface &res)
{
SDL_Surface *img = IMG_Load(key.c_str());
//error checking and such here
res = *img;
}
OnFreeResource(SDL_Surface *surf)
{
SDL_FreeSurface(surf);
}
}
Using insert solves the problem of leaking my original pointer, thanks.
However, I can't call SDL_FreeSurface on the item, i get an access violation segfault when I try to do so.
I'll give a go at using a regular map with a custom deleter and let you know how that goes.
Alright, i think I've almost got this sorted out.
I'm trying to create a virtual function to act as a deleter for an std::shared_ptr (swapped to shared_ptr because there are going to be numerous references to the same pointer).
template<class T>
class ResourceManager
{
//leaving out ctors and such that aren't important atm
private:
typedef std::shared_ptr<T> ptr_t;
typedeftypename std::map<std::string, ptr_t> map_t;
typedeftypename map_t::iterator map_i;
protected:
virtualvoid OnLoadResource(std::string &key) {}
virtualvoid OnFreeResource(T *t) {}
private:
ptr_t &Load(std::string &key)
{
map_i i = m_map.find(key);
if(i != m_map.end())
return i->second; //return it if it exists
ptr_t p(new T, OnFreeResource/*set deleter here*/); //I want the deleter to run the virtual function OnFreeResource
OnLoadResource(key, *p); //otherwise load it
m_map.insert(std::make_pair(key, std::move(p)));
return m_map[key];
}
private:
map_t m_map;
}
The method to delete an object needs to be virtual because different types of objects will need to be released different ways.
When I get to using it, i get a compiler error telling me
function call missing argument list; use '&ResourceManager<int>::OnFreeResource' to create a pointer to member
So I tried to listen to it and make a reference to the function OnFreeResource, and got
'&' : illegal operation on bound member function expression
Can you use a virtual member function to create an alternative deleter for shared_ptr? Can you even do that with a function or do you need something like boost::function? Or am I going about this entirely wrong?
Thanks in advance for the help.
EDIT:
solved my problem.
Changed the template on resource manager to
1 2 3 4 5 6
template<class T, class deleter = std::default_delete<T>>
class ResourceManager
{
//....
ptr_t p(new T, deleter());
};
then defined a struct called SurfaceDeleter and overloaded the () operator to apply SDL_FreeSurface.