web-dev-qa-db-ja.com

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>)'
_

私は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クラスの外側に移動すると、コードがコンパイルされます。問題を引き起こしているDeleteSurfaceクラスにGame関数を含めることについてはどうですか?

38
Wheels2050
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または他のメンバー関数ポインターアダプター。

52
ronag

このコードは、オブジェクトメソッドとして削除機能を使用した共有ポインターの構築例を示しています。使用する_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));
    }
}
_
10
chmike