web-dev-qa-db-fra.com

Utilisation de deleter personnalisé avec std :: shared_ptr

J'essaie de savoir comment utiliser std :: shared_ptr avec un suppresseur personnalisé. Plus précisément, je l'utilise avec SDL_Surface en tant que:

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

qui compile et fonctionne bien. Cependant, je voudrais essayer mon propre délétère et je ne peux pas trouver comment le faire. La documentation de SDL_FreeSurface se trouve ici:

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

dans lequel je trouve que la SDL_FreeSurface est déclarée comme:

void SDL_FreeSurface(SDL_Surface* surface);

À titre de test, et en fonction de ces informations, j'ai essayé la fonction suivante:

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

Cependant, la compilation avec g ++ me donne l'erreur suivante:

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

J'ai regardé la documentation gnu pour l'implémentation de gcc std :: shared_ptr mais je ne peux pas lui donner beaucoup de sens. Qu'est-ce que je fais mal?

EDIT: J'ai depuis réduit le problème, mais je vais laisser la question d'origine ci-dessus. Ce que j'avais était une classe de jeu qui, si je la déduisais d'une implémentation de base, ressemblait à:

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 */
}

avec l'implémentation de DeleteSurface comme ci-dessus, et l'implémentation de CacheImages() comme:

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

quel jeu me l'erreur que j'ai énumérée ci-dessus. Cependant, si je déplace la fonction DeleteSurface() en dehors de la classe Game sans la modifier autrement, le code se compile. En quoi consiste l'inclusion de la fonction DeleteSurface dans la classe Game qui pose problème?

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

ou

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

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

MODIFIER:

En voyant votre question mise à jour, DeleteSurface devrait être une fonction non membre, sinon vous devez utiliser std::bind ou std::mem_fn ou un autre adaptateur de pointeur de fonction membre.

52
ronag

Ce code fournit un exemple de construction de pointeur partagé avec le suppresseur comme méthode d'objet. Il affiche l'instruction std::bind À utiliser.

L'exemple est un simple recycleur d'objets. Lorsque la dernière référence à l'objet est détruite, l'objet est renvoyé au pool d'objets libres à l'intérieur du recycleur.

Le recyler peut être facilement transformé en cache d'objets en ajoutant une clé aux méthodes get() et add() et en stockant les objets dans 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));
    }
}
10
chmike