2012-09-09 14 views
27

Estoy tratando de encontrar la forma de usar std :: shared_ptr con un eliminador personalizado. En concreto, lo estoy usando con SDL_Surface como:Uso del eliminador personalizado con std :: shared_ptr

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

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

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

en el que encuentro la SDL_FreeSurface se declara como:

void SDL_FreeSurface(SDL_Surface* surface); 

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

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

Sin embargo, se compila 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 consultado la documentación de gnu para la implementación de gcc std :: shared_ptr, pero no puedo darle mucho sentido. ¿Qué estoy haciendo mal?

EDITAR: Desde entonces he reducido el problema, pero dejaré la pregunta original anterior. Lo que tenía era una clase de juego que, si se me tira hacia abajo a una implementación básica, era algo así 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 que el anterior, y la implementación de CacheImages() como:

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

que juego el error que enumeré arriba. Sin embargo, si muevo la función DeleteSurface() fuera de la clase Game sin alterarla de otra manera, el código se compila. ¿De qué se trata al incluir la función DeleteSurface en la clase Game que está causando problemas?

+0

Su ejemplo compila bien para mí. –

Respuesta

42
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); 

EDIT:

ver a su pregunta actualizada, DeleteSurface debería ser una función no miembro, de lo contrario es necesario utilizar std::bind o std::mem_fn o algún otro adaptador de puntero de función miembro .

+0

Su segundo ejemplo es lo que ya tenía, que no compilará. – Wheels2050

+0

@ Wheels2050: Se compila muy bien, en este caso está dejando algo fuera de su ejemplo. – ronag

+0

Lo sentimos, tienes razón. He editado mi pregunta. – Wheels2050

8

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

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

El reciclador se puede cambiar fácilmente en un caché de objetos al agregar una clave a los métodos get() y add() y al almacenar 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)); 
    } 
} 
+1

Solo quería decir que esto no funciona como se esperaba. Cuando llame a 'get()', ** siempre ** obtendrá un puntero compartido con un recuento de referencia de '1'. Lo que es peor, múltiples punteros compartidos pueden apuntar a la misma memoria. Si uno sale del alcance, obtendrá segfaults. Lo que necesita no es un 'std :: vector ', sino un 'std :: vector >'. – rwols

+0

no desea un 'std :: vector >' porque eso no conservará la vida útil del búfer que desea reutilizar, quiere un 'std :: vector > 'en cambio. puede crear implícitamente un 'std :: shared_ptr' desde su' std :: unique_ptr' preexistente y luego el eliminador personalizado puede tomar el puntero actual sin dueño y colocarlo en un nuevo 'std :: unique_ptr' y ponerlo eso en su 'std :: vector'. –

Cuestiones relacionadas