【问题标题】:Problems using member function as custom deleter with std::shared_ptr使用成员函数作为自定义删除器与 std::shared_ptr 的问题
【发布时间】:2012-09-02 16:15:39
【问题描述】:

我正在尝试研究如何将 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>)'

我查看了 gcc std::shared_ptr 实现的 gnu 文档,但无法理解它。我做错了什么?

编辑:我已经缩小了问题的范围,但会留下上面的原始问题。我所拥有的是一个 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() 的实现如:

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

我上面列出的错误是哪个游戏我。但是,如果我将 DeleteSurface() 函数移到 Game 类之外而不进行其他更改,则代码将编译。在引起问题的Game 类中包含DeleteSurface 函数是什么意思?

【问题讨论】:

  • 你的例子对我来说编译得很好。

标签: c++ sdl shared-ptr


【解决方案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);

编辑:

看到你更新的问题,DeleteSurface应该是非成员函数,否则需要使用std::bind或者std::mem_fn或者其他一些成员函数指针适配器。

【讨论】:

  • 你的第二个例子是我已经有的,它不会编译。
  • @Wheels2050:它编译得很好,在这种情况下,你会从你的例子中遗漏一些东西。
  • 谢谢。我仍然不明白为什么成员函数不起作用,但你已经向我展示了要调查的内容。
  • @Wheels2050:需要在Game 的实例上调用非静态成员函数,这将是成员函数内部this 指向的对象指针。 shared_ptr 在调用删除函数时没有Game 的实例。
  • 这里实际上没有捕获任何东西,是吗?您的 lambda 捕获组中可能不应该有 =;我发现它令人困惑。
【解决方案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));
    }
}

【讨论】:

  • 只是想说这不能按预期工作。当您调用get() 时,您将始终获得引用计数为1 的共享指针。更糟糕的是,多个共享指针可以指向同一个内存。如果一个超出范围,你会得到段错误。你需要的不是std::vector&lt;Obj*&gt;,而是std::vector&lt;std::weak_ptr&lt;Obj&gt;&gt;
  • 您不需要std::vector&lt;std::weak_ptr&lt;Obj&gt;&gt;,因为这不会保留您要重用的缓冲区的生命周期,而是需要std::vector&lt;std::unique_ptr&lt;Obj&gt;&gt;。您可以从预先存在的std::unique_ptr 隐式创建std::shared_ptr,然后自定义删除器可以获取原始的现在未拥有的指针并将其放入新的std::unique_ptr 并将其放入您的std::vector。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-17
  • 2020-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多