2015-04-15 30 views
11

Hãy nói rằng tôi muốn sử dụng một deleter tuỳ chỉnh với một unique_ptr:Tại sao unique_ptr không thể suy ra loại deleter?

void custom_deleter(int* obj) 
{ 
    delete obj; 
} 

Tại sao tôi phải viết này:

std::unique_ptr<int, void(*)(int*)> x(new int, custom_deleter); 

thay vì điều này:

std::unique_ptr<int> x(new int, custom_deleter); //does not compile 

?

Không thể suy ra loại suy luận?

+1

Related: http://stackoverflow.com/questions/21355037/why-does-unique-ptr-take-two-template-parameters-when-shared-ptr-only-takes-one – 0x499602D2

+4

Lớp mẫu không suy ra các tham số mẫu. Chỉ các hàm mẫu mới có. –

+3

Tôi tự hỏi tại sao 'std :: make_unique' không có quá tải trong đó bạn có thể chỉ định deleter. Bằng cách này, bạn có thể suy ra loại của deleter. – vsoftco

Trả lời

6

Đối unique_ptr, các deleter là một phần của các loại:

template < 
    class T, 
    class Deleter = std::default_delete<T> 
> class unique_ptr; 

Như vậy, khi bạn đang xây dựng một đối tượng, bạn cần phải xác định loại của nó. Điểm mấu bạn đang viết:

std::unique_ptr<int> x(new int, custom_deleter); 

tương đương với:

std::unique_ptr<int, std::default_delete<int> > x(new int, custom_deleter); 

Và bạn không thể xây dựng một std::default_delete<int> từ custom_deleter.

Cách duy nhất để suy luận loại deleter là sử dụng mẫu khấu trừ vào phần đó quá:

template <typename T, typename Deleter> 
std::unique_ptr<T, Deleter> make_unique_ptr(T* ptr, Deleter deleter) { 
    return std::unique_ptr<T, Deleter>(ptr, deleter); 
} 
+0

đó chính xác là những gì tôi đã làm cho 'std :: make_unique', không thấy lý do nào tại sao nó không được thực hiện như thế. – vsoftco

+2

@vsoftco [sao chép từ trên cao] Cách hoạt động? Nó phải có một gói đối số để xây dựng T. Làm thế nào bạn sẽ phân biệt một trong những Args ... là Deleter? – Barry

+0

có thể với một 'std :: piecewise_construct' /' std :: forward_as_tuple' – vsoftco

3

Nó không thể suy ra các loại của deleter, vì unique_ptr theo mặc định không có nhà nước dành cho một deleter: deleter mặc định là không trạng thái.

Trong trường hợp của bạn, dấu phân cách cần giá trị của con trỏ, vì vậy nó không thể 'vừa' trong trạng thái của std::unique_ptr (chỉ là con trỏ đến số T).

Điều này làm cho unique_ptr thay thế nhẹ, gần như miễn phí cho một con trỏ sở hữu.

Deductin có thể được thực hiện, nhưng nó sẽ phải thay đổi loại kết quả unique_ptr.

Khi so sánh, shared_ptr luôn có khả năng trạng thái cho một dấu phân cách, hai bộ đếm nguyên tử khác nhau và một con trỏ tới giá trị. Đó là trọng lượng nặng hơn, và không phải là một thay thế miễn phí cho một con trỏ.

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