2015-02-19 15 views
5

Tôi đang cố gắng sử dụng unique_ptr với một tùy chỉnh deleter cho SDL_Surface loại. Đây chỉ là một ví dụ sử dụng loại int, nhưng tôi hy vọng bạn sẽ có được ý tưởng.Bối rối bằng cách sử dụng unique_ptr và một tùy chỉnh deleter

#include <iostream> 
#include <functional> 
#include <memory> 

typedef int SDL_Surface; 


SDL_Surface * CreateSurface() 
{ 
    SDL_Surface * p = new SDL_Surface; 
    return p; 
} 

void FreeSurface(SDL_Surface *p) 
{ 
    delete p; 
} 

int main() { 
    std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *) > > uptr_1; 

    //how to assign a value to uptr_1 and the deleter? 

    return 0; 
} 

uptr_1 được khai báo chính xác và được khởi tạo thành nullptr? Nếu vậy, làm thế nào tôi có thể gán con trỏ và chức năng deleter?

Và làm cách nào tôi có thể gói gọn điều này: std::unique_ptr< SDL_Surface, std::function< void (SDL_Surface *) > > với công cụ không phải lúc nào cũng viết dòng đó trên mỗi SDL_Surface Tôi muốn, một typedef khác?

Tôi chỉ mới bắt đầu tìm hiểu các tính năng C++ 11 và đây là một tính năng khó đối với tôi.

+0

'std :: unique_ptr > uptr_1 (CreateSurface (), & :: FreeSurface); ' –

+5

' std :: function' là một sự lựa chọn nghèo cho một deleter trong trường hợp chung, bởi vì các hàm tạo của nó có thể ném, nhưng constructor của 'unique_ptr''s deleter không được ném. Tuy nhiên, nếu bạn chỉ sử dụng nó với một con trỏ hàm đơn giản, nó an toàn. –

+0

Liên quan - https://stackoverflow.com/q/24251747/241631 – Praetorian

Trả lời

10

Bạn có thể khởi tạo unique_ptr với một con trỏ và deleter, hoặc sử dụng = thường nếu tái gán sau:

std::unique_ptr<SDL_Surface, std::function<void (SDL_Surface *)>> uptr_1(CreateSurface(), &FreeSurface); 

uptr_1 = std::unique_ptr<SDL_Surface, std::function<void (SDL_Surface *)>>(CreateSurface(), &FreeSurface); 

Tham khảo suitable docs để biết chi tiết.

Để rút ngắn kiểu dài, bạn thực sự có thể sử dụng một loại bí danh (typedef hay using):

typedef std::unique_ptr<SDL_Surface, void (*)(SDL_Surface*)> Surface_ptr; 

//or 

using Surface_ptr = std::unique_ptr<SDL_Surface, void (*)(SDL_Surface*)>; 

Thông báo Tôi đã thực sự sử dụng void (*)(SDL_Surface*) cho các loại deleter. Nếu bạn biết bạn sẽ luôn luôn vượt qua một chức năng thực tế (hoặc lambda không quốc tịch) trong, không có lý do để kéo trong std::function, trong đó có một số chi phí do xóa loại.

Ngoài ra, bạn có thể rút ngắn nó hơn nữa bằng cách tạo ra một functor mặc định-constructible cho deleter:

struct FreeSurface_Functor 
{ 
    void operator() (SDL_Surface *s) const 
    { 
    FreeSurface(s); 
    } 
}; 

Bằng cách đó, bạn có thể làm các loại con trỏ của bạn std::unique_ptr<SDL_Surface, FreeSurface_Functor> (có thể là bí danh) và bạn don' t phải cung cấp các deleter; nó sẽ được mặc định-xây dựng:

std::unique_ptr<SDL_Surface, FreeSurface_Functor> uptr_1(CreateSurface()); 
+0

tôi có phải kiểm tra trong deleter tùy chỉnh nếu con trỏ là nullptr không? Hoặc std :: unique_ptr sẽ không gọi deleter mặc định nếu con trỏ là nullptr? Cảm ơn câu trả lời. – FrameBuffer

+1

@FrameBuffer Bạn không phải kiểm tra. 'unique_ptr' được đảm bảo thực hiện kiểm tra cho bạn, và chỉ gọi deleter nếu không null. Bạn có thể tìm thấy nội dung như vậy trong [tài liệu tôi đã liên kết] (http://en.cppreference.com/w/cpp/memory/unique_ptr/~unique_ptr). – Angew

+5

Bạn có thể chỉ ra rằng kỹ thuật xác định loại lớp không có trạng thái vô hạn được ưu tiên vì việc triển khai 'unique_ptr' chất lượng sẽ tối ưu hóa bộ nhớ của chúng với Tối ưu hóa cơ sở trống. – Casey

1

là uptr_1 tuyên bố một cách chính xác và khởi tạo nullptr

Vâng, một mặc định xây dựng unique_ptr sẽ giới thiệu để null.

nếu có, làm cách nào để gán con trỏ và chức năng deleter?

Bạn nên xây dựng unique_ptr với đối số

std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *) > > uptr_1{CreateSurface(), FreeSurface}; 

Ngoài ra, sau khi xây dựng mặc định, bạn có thể sử dụng phân di chuyển với một tạm thời

uptr_1 = std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *) > >{CreateSurface(), FreeSurface}; 

Như bạn đã gợi ý cho mình, một loại bí danh có thể giúp

using SDL_Uptr = std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *)>>; 
SDL_Uptr uptr_1; 
uptr_1 = SDL_Uptr{CreateSurface(), FreeSurface}; 

Một chức năng trung gian có thể giúp đơn giản hóa điều này nếu nó trở thành lặp đi lặp lại (có thể nó sẽ xảy ra nếu bạn thực hiện rất nhiều).

std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> 
make_sdl_ptr() { 
    return std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)>{CreateSurface(), FreeSurface}; 
} 

Sau đó, bạn có thể gọi đây là với auto uptr = make_sdl_ptr();

câu trả lời Angew với một deleter DefaultConstructible gọi chức năng của bạn cũng là một giải pháp thật sự tốt đẹp.

0

tôi sẽ đi với decltype:

std::unique_ptr<SDL_Surface, decltype(&FreeSurface)> uptr_1(
      CreateSurface(), 
      FreeSurface 
); 
Các vấn đề liên quan