2012-09-09 31 views
27

Sto cercando di capire come usare std :: shared_ptr con un deleter personalizzato. Nello specifico, lo sto usando con SDL_Surface come:Utilizzo deleter personalizzato con std :: shared_ptr

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

che compila e funziona correttamente. Tuttavia, mi piacerebbe provare il mio personale deleter e non riesco a capire come farlo. La documentazione per SDL_FreeSurface si trova qui:

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

in cui trovo lo SDL_FreeSurface è dichiarato come:

void SDL_FreeSurface(SDL_Surface* surface); 

Come test, e andando da tali informazioni, ho provato la seguente funzione:

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

Tuttavia, la compilazione con g ++ mi dà il seguente errore:

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

Ho esaminato la documentazione di gnu per l'implementazione gcc std :: shared_ptr ma non posso dare molto senso a questo. Che cosa sto facendo di sbagliato?

EDIT: Ho quindi ristretto il problema, ma lascerò la domanda originale sopra. Quello che avevo era una classe di gioco che, se mi striscia verso il basso ad un'implementazione di base, era qualcosa di simile:

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 l'attuazione di DeleteSurface come sopra, e l'implementazione di CacheImages() come:

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

che mi fa l'errore che ho elencato sopra. Tuttavia, se sposto la funzione DeleteSurface() all'esterno della classe Game senza alterarla in altro modo, il codice viene compilato. Di cosa si tratta includendo la funzione DeleteSurface nella classe Game che causa problemi?

+0

Il tuo esempio si compila bene per me. –

risposta

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:

vedere la tua domanda aggiornato, DeleteSurface dovrebbe essere una funzione non membro, in caso contrario è necessario utilizzare std::bind o std::mem_fn o qualche altro adattatore puntatore a funzione membro .

+0

Il tuo secondo esempio è quello che ho già avuto, che non verrà compilato. – Wheels2050

+0

@ Wheels2050: compila bene, in questo caso stai lasciando fuori qualcosa dal tuo esempio. – ronag

+0

Siamo spiacenti, hai ragione - Ho modificato la mia domanda. – Wheels2050

8

Questo codice fornisce un esempio di una costruzione di puntatore condivisa con il deleter come metodo di oggetto. Visualizza l'istruzione std::bind da utilizzare.

L'esempio è un semplice riciclatore di oggetti. Quando l'ultimo riferimento all'oggetto viene distrutto, l'oggetto viene restituito al pool di oggetti liberi all'interno del recycler.

Il recyler può essere facilmente modificato in una cache di oggetti aggiungendo una chiave ai metodi get() e add() e memorizzando gli oggetti in 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

Volevo solo dire che questo non funziona come previsto. Quando chiami 'get()', avrai ** sempre ** un puntatore condiviso con un conteggio di riferimento di '1'. Quel che è peggio, più puntatori condivisi possono quindi puntare alla stessa memoria. Se si esce dal campo di applicazione, si otterranno segfault. Quello di cui hai bisogno non è un 'std :: vector ', ma un 'std :: vector >'. – rwols

+0

non si desidera un 'std :: vector >' poiché ciò non preserverà la durata del buffer che si desidera riutilizzare, si desidera un 'std :: vector > invece. puoi creare implacabilmente un 'std :: shared_ptr' dal tuo' std :: unique_ptr' preesistente e poi il delet personalizzato può quindi prendere il puntatore non sincronizzato e adesso metterlo in un nuovo 'std :: unique_ptr' e mettere quello nel tuo 'std :: vector'. –

Problemi correlati