Usando deleter personalizado con std:: ptr compartido


Estoy tratando de averiguar cómo usar std::shared_ptr con un deleter personalizado. Específicamente, lo estoy usando con SDL_Surface como:

std::shared_ptr<SDL_Surface>(SDL_LoadBMP(....),SDL_FreeSurface);

Que compila y funciona bien. Sin embargo, me gustaría probar mi propio deleter y no puedo encontrar la manera de hacerlo. La documentación para SDL_FreeSurface se encuentra aquí:

Http://sdl.beuc.net/sdl.wiki/SDL_FreeSurface

En el que encuentro que el SDL_FreeSurface se declara como:

void SDL_FreeSurface(SDL_Surface* surface);

Como prueba, y pasando esa información, probé la siguiente función:

void DeleteSurface(SDL_Surface* surface)
{
    std::cout << "Deleting surface\n";
    SDL_FreeSurface(surface);
}

Sin embargo, compilar con g++ me da el siguiente error:

error: no matching function for call to 'std::shared_ptr<SDL_Surface>::shared_ptr(SDL_Surface*, <unresolved overloaded function type>)'

He visto la documentación de gnu para la implementación de gcc std::shared_ptr pero no le puedo dar mucho sentido. ¿Qué estoy haciendo mal?

EDITAR: Desde entonces he reducido el problema, pero dejaré la pregunta original arriba. Lo que tenía era una clase de Juego que, si lo descortezaba a una implementación básica, era algo como:

class Game {
    public:
        /* various functions */
    private:
        void DeleteSurface(SDL_Surface* surface);
        bool CacheImages();
        std::vector<std::shared_ptr<SDL_Surface> > mCachedImages;

        /* various member variables and other functions */
}

Con la implementación de DeleteSurface como antes, y la implementación de CacheImages() como:

bool CacheImages()
{
    mCachedImages.push_back(std::shared_ptr<SDL_Surface>(SDL_LoadBMP(...),DeleteSurface);
    return true;
}

¿Qué juego me el error que he enumerado anteriormente. Sin embargo, si muevo la función DeleteSurface() fuera de la clase Game sin alterarla, el código se compila. ¿De qué se trata incluir la función DeleteSurface en la clase Game que está causando problemas?

Author: Wheels2050, 2012-09-09

2 answers

std::shared_ptr<SDL_Surface>(SDL_LoadBMP(....), [=](SDL_Surface* surface)
{
    std::cout << "Deleting surface\n";
    SDL_FreeSurface(surface);
});

O

void DeleteSurface(SDL_Surface* surface)
{
    std::cout << "Deleting surface\n";
    SDL_FreeSurface(surface);
}

std::shared_ptr<SDL_Surface>(SDL_LoadBMP(....), DeleteSurface);

EDITAR:

Al ver su pregunta actualizada, DeleteSurface debe ser una función no miembro, de lo contrario debe usar std::bind o std::mem_fn o algún otro adaptador de puntero de función miembro.

 46
Author: ronag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-09 16:59:43

Este código proporciona un ejemplo de construcción de puntero compartido con el deleter como método objeto. Muestra la instrucción std::bind a utilizar.

El ejemplo es un simple reciclador de objetos. Cuando se destruye la última referencia al objeto, el objeto se devuelve al grupo de objetos libres dentro del reciclador.

El recyler se puede cambiar fácilmente a una caché de objetos agregando una clave a los métodos get() y add() y almacenando los objetos en un std::map.

class ObjRecycler
{
private:
    std::vector<Obj*> freeObjPool;
public:
    ~ObjRecycler()
    {
        for (auto o: freeObjPool)
            delete o;
    }

    void add(Obj *o)
    {
        if (o)
            freeObjPool.push_back(o);
    }

    std::shared_ptr<Obj> get()
    {
        Obj* o;
        if (freeObjPool.empty())
            o = new Obj();
        else
        {
            o = freeObjPool.back();
            freeObjPool.pop_back();
        }
        return std::shared_ptr<Obj>(o, 
             std::bind(&ObjRecycler::add, this, std::placeholders::_1));
    }
}
 9
Author: chmike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-17 14:17:48