Подтвердить что ты не робот

Использование пользовательского удаления с помощью std:: shared_ptr

Я пытаюсь решить, как использовать std:: shared_ptr с пользовательским удалением. В частности, я использую его с SDL_Surface как:

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

который компилируется и работает нормально. Тем не менее, я хотел бы попробовать собственный дебит и не могу решить, как это сделать. Документация для SDL_FreeSurface находится здесь:

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

в котором я обнаружил, что SDL_FreeSurface объявлен как:

void SDL_FreeSurface(SDL_Surface* surface);

В качестве теста и перехода по этой информации я попытался выполнить следующую функцию:

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

Однако компиляция с g++ дает мне следующую ошибку:

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

Я просмотрел документацию gnu для реализации gcc std:: shared_ptr, но не могу ее полностью понять. Что я делаю неправильно?

EDIT: Я с тех пор сузил проблему, но оставил исходный вопрос выше. У меня был класс Game, который, если бы я разделил его на базовую реализацию, был примерно таким:

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

с реализацией DeleteSurface, как указано выше, и реализация CacheImages() as:

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

какая игра мне ошибка, которую я перечислил выше. Однако, если я перемещаю функцию DeleteSurface() вне класса Game, не изменяя ее иным образом, компиляция кода. Что такое включение функции DeleteSurface в класс Game, вызывающий проблемы?

4b9b3361

Ответ 1

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

или

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

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

EDIT:

Увидев ваш обновленный вопрос, DeleteSurface должен быть нечленом, иначе вам нужно использовать std::bind или std::mem_fn или какой-либо другой адаптер указателя на функцию-член.

Ответ 2

Этот код представляет собой пример построения общего указателя с делетером как метод объекта. Он отображает инструкцию std::bind.

Примером является простой объект-рециклинг. Когда последняя ссылка на объект уничтожается, объект возвращается в пул свободных объектов внутри ресайклера.

Рекайлер можно легко изменить в кеш объекта, добавив ключ к методам get() и add() и сохраняя объекты в 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));
    }
}