Использование пользовательского удаления с помощью 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
, вызывающий проблемы?
Ответы
Ответ 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));
}
}