2012-09-09 43 views
27

Tôi đang cố gắng tìm ra cách sử dụng std :: shared_ptr với một deleter tùy chỉnh. Cụ thể, tôi đang sử dụng nó với SDL_Surface là:Sử dụng deleter tùy chỉnh với std :: shared_ptr

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

biên dịch và chạy tốt. Tuy nhiên, tôi muốn thử những người yêu thích của riêng tôi và không thể tìm ra cách để làm như vậy. Các tài liệu cho SDL_FreeSurface được tìm thấy ở đây:

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

trong đó tôi tìm ra SDL_FreeSurface được khai báo là:

void SDL_FreeSurface(SDL_Surface* surface); 

Là một thử nghiệm, và đi bằng thông tin rằng, tôi đã thử chức năng sau:

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

Tuy nhiên, biên soạn với g ++ mang lại cho tôi những lỗi sau:

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

Tôi đã xem tài liệu về gnu cho gcc std :: shared_ptr implementation nhưng không thể hiểu nhiều về nó. Tôi đang làm gì sai?

EDIT: Tôi đã thu hẹp vấn đề, nhưng sẽ để nguyên câu hỏi gốc ở trên. Những gì tôi đã có được một lớp học trò chơi mà, nếu tôi lột nó xuống đến một thực hiện cơ bản, là một cái gì đó như:

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

với việc thực hiện DeleteSurface như trên, và thực hiện các CacheImages() như:

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

làm tôi bị lỗi khi liệt kê ở trên. Tuy nhiên, nếu tôi di chuyển hàm DeleteSurface() bên ngoài lớp Game mà không thay đổi nó, thì mã sẽ biên dịch. Điều gì về việc bao gồm hàm DeleteSurface trong lớp Game gây ra sự cố?

+0

Ví dụ của bạn biên soạn tốt cho tôi. –

Trả lời

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

hoặc

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

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

EDIT:

Thấy câu hỏi cập nhật của bạn, DeleteSurface phải là một chức năng phi thành viên, nếu không bạn cần phải sử dụng std::bind hoặc std::mem_fn hoặc một số chức năng thành viên con trỏ bộ chuyển đổi khác .

+0

Ví dụ thứ hai của bạn là những gì tôi đã có, mà sẽ không biên dịch. – Wheels2050

+0

@ Wheels2050: Nó biên dịch tốt, bạn đang để lại một cái gì đó từ ví dụ của bạn trong trường hợp đó. – ronag

+0

Xin lỗi, bạn nói đúng - Tôi đã chỉnh sửa câu hỏi của mình. – Wheels2050

8

Mã này cung cấp ví dụ về cấu trúc con trỏ được chia sẻ với dấu phân cách làm phương thức đối tượng. Nó hiển thị hướng dẫn sử dụng std::bind.

Ví dụ này là trình tái chế đối tượng đơn giản. Khi tham chiếu cuối cùng cho đối tượng bị hủy, đối tượng được trả về nhóm đối tượng miễn phí bên trong trình tái chế.

Các recyler có thể dễ dàng thay đổi thành một bộ nhớ cache đối tượng bằng cách thêm một chìa khóa dẫn đến get()add() phương pháp và bằng cách lưu trữ các đối tượng trong một 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)); 
    } 
} 
+1

Chỉ muốn nói rằng điều này không hoạt động như dự định. Khi bạn gọi 'get()', bạn sẽ luôn luôn ** nhận được một con trỏ được chia sẻ với số tham chiếu là '1'. Tệ hơn nữa, nhiều con trỏ được chia sẻ sau đó có thể trỏ đến cùng một bộ nhớ. Nếu một trong số đó đi ra khỏi phạm vi, bạn sẽ nhận được segfaults. Những gì bạn cần không phải là 'std :: vector ', nhưng một 'std :: vector >'. – rwols

+0

bạn không muốn một 'std :: vector >' vì điều đó sẽ không giữ được tuổi thọ của bộ đệm bạn muốn sử dụng lại, bạn muốn có 'std :: vector > 'thay thế. bạn có thể tạo ra một 'std :: shared_ptr' từ« std :: unique_ptr' tồn tại trước đó của bạn và sau đó deleter tùy biến có thể lấy con trỏ thô không được thừa nhận và đặt nó vào một 'std :: unique_ptr' mới và đặt mà vào 'std :: vector' của bạn. –

Các vấn đề liên quan