2012-09-09 95 views
27

我想解決如何使用std :: shared_ptr與自定義刪除。具體來說,我使用它作爲SDL_Surface:使用定製刪除與std :: shared_ptr

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文檔的gd std :: shared_ptr實現,但是不能理解它。我究竟做錯了什麼?

編輯:我已經縮小了這個問題,但會留下上面的原始問題。我曾是一個遊戲類,如果我剝它歸結爲一個基本的實現,是這樣的:

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類中是什麼?

+0

你的例子對我來說編譯得很好。 –

回答

42
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::bindstd::mem_fn或其他一些成員函數指針適配器。

+0

你的第二個例子是我已經有的,它不會編譯。 – Wheels2050

+0

@ Wheels2050:它編譯得很好,在這種情況下,你正在從你的例子中留下一些東西。 – ronag

+0

對不起,你是對的 - 我編輯了我的問題。 – Wheels2050

8

此代碼提供了一個以deleter作爲對象方法的共享指針構造示例。它顯示要使用的指令std::bind

該示例是一個簡單的對象回收器。當對象的最後一個引用被銷燬時,該對象將返回到回收站內的空閒對象池。

通過在get()add()方法中添加一個密鑰並將對象存儲在std::map中,可以輕鬆地將recyler更改爲對象緩存。

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)); 
    } 
} 
+1

只是想說這不符合預期。當你調用get()時,你總是會得到一個引用計數爲1的共享指針。更糟的是,多個共享指針可以指向相同的內存。如果一個超出範圍,你會得到段錯誤。你需要的不是'std :: vector ',而是'std :: vector >'。 – rwols

+0

你不想要'std :: vector >'因爲這樣不會保留你想要重用的緩衝區的生命週期,你想要一個'std :: vector >代替。你可以從你已有的std :: unique_ptr中毫不留情地創建一個'std :: shared_ptr',然後定製的刪除器可以取得原始的現在無主的指針,並將它放入一個新的'std :: unique_ptr'中,到你的'std :: vector'中。 –

相關問題