Freeing resources with Boost::ptr_map

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;
typedef template 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.
Last edited on
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)
Last edited on
Thanks for the help, Cubbi.
Maybe i can elaborate more.
I've structured my code like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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:
    virtual void OnLoadResource(std::string key);
    virtual void 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.
Last edited on
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).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template<class T>
class ResourceManager
{
//leaving out ctors and such that aren't important atm
private:
    typedef std::shared_ptr<T> ptr_t;
    typedef typename std::map<std::string, ptr_t> map_t;
    typedef typename map_t::iterator map_i;

protected:
    virtual void OnLoadResource(std::string &key) {}
    virtual void 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.
Last edited on
Topic archived. No new replies allowed.