2014-04-17 22 views
12

Tại sao shared_ptr có allocate_shared trong khi unique_ptr không có allocate_unique?
Tôi muốn tạo một unique_ptr bằng cách sử dụng trình phân bổ của riêng mình: tôi có phải phân bổ bộ đệm cho chính mình và sau đó gán nó cho một unique_ptr không?
Điều này có vẻ giống như một thành ngữ rõ ràng.Tại sao không có hàm std :: allocate_unique trong C++ 14?

Trả lời

12

Tại sao shared_ptrallocate_shared khi unique_ptr không có allocate_unique?

shared_ptr cần nó để nó có thể phân bổ trạng thái chia sẻ nội bộ của nó (số tham chiếu và deleter), cũng như đối tượng dùng chung, sử dụng trình phân bổ. unique_ptr chỉ quản lý đối tượng; do đó, không cần phải cung cấp một cấp phát cho chính số unique_ptr và ít cần cho một hàm allocate.

(Cũng cần ít hơn make_unique vì lý do tương tự, đó có thể là lý do tại sao nó không có trong C++ 11, nhưng được thêm vào C++ 14 theo nhu cầu phổ biến vì mục đích nhất quán. Có thể nhu cầu tương tự sẽ thêm allocate_unique vào tiêu chuẩn tương lai.)

tôi có phải tự phân bổ bộ đệm và sau đó gán cho nó một unique_ptr không?

Có. Hoặc bạn có thể viết allocate_unique của riêng bạn; không giống như allocate_shared, nó có thể, và hợp lý đơn giản, để thực hiện nó một cách riêng biệt từ unique_ptr chính nó. (Như đã đề cập trong các ý kiến, bạn phải chắc chắn rằng nó đã sử dụng một deleter thích hợp cho các cấp phát; các deleter mặc định sẽ sử dụng delete và đi sai khủng khiếp).

Điều này có vẻ giống như một thành ngữ hiển nhiên.

Thật vậy. Nhưng rất nhiều thành ngữ khác, và không phải mọi thứ đều có thể (hoặc nên) được chuẩn hóa.

Để có biện minh chính thức hơn về tình trạng thiếu hiện tại allocate_unique, hãy xem proposal for make_unique, cụ thể là phần 4 (Thông số tùy chỉnh).

+3

+1. Khía cạnh loại tẩy xóa được đề cập trong đề xuất là IMHO quan trọng nhất, loại trả về 'allocate_unique' sẽ là loại nào? –

+0

@JonathanWakely: Điểm tốt. Có lẽ tuyên bố của tôi rằng nó "hợp lý đơn giản" có thể thay đổi nếu tôi thực sự cố gắng làm điều đó. –

12

tôi có phải tự phân bổ bộ đệm và sau đó gán nó cho unique_ptr không?

Không chỉ là bộ đệm, con trỏ đến đối tượng. Nhưng đối tượng có thể cần phải được phân bổ bởi người cấp phát, và bộ nhớ chắc chắn cần phải deallocated bởi các cấp phát, vì vậy bạn cũng cần phải vượt qua các cấp phát các unique_ptr. Nó không biết làm thế nào để sử dụng một cấp phát, vì vậy bạn cần phải bọc nó trong một deleter tùy chỉnh, và đó sẽ trở thành một phần của kiểu của unique_ptr.

Tôi nghĩ rằng một giải pháp chung chung sẽ giống như thế này:

#include <memory> 

template<typename Alloc> 
struct alloc_deleter 
{ 
    alloc_deleter(const Alloc& a) : a(a) { } 

    typedef typename std::allocator_traits<Alloc>::pointer pointer; 

    void operator()(pointer p) const 
    { 
    Alloc aa(a); 
    std::allocator_traits<Alloc>::destroy(aa, std::addressof(*p)); 
    std::allocator_traits<Alloc>::deallocate(aa, p, 1); 
    } 

private: 
    Alloc a; 
}; 

template<typename T, typename Alloc, typename... Args> 
auto 
allocate_unique(const Alloc& alloc, Args&&... args) 
{ 
    using AT = std::allocator_traits<Alloc>; 
    static_assert(std::is_same<typename AT::value_type, std::remove_cv_t<T>>{}(), 
       "Allocator has the wrong value_type"); 

    Alloc a(alloc); 
    auto p = AT::allocate(a, 1); 
    try { 
    AT::construct(a, std::addressof(*p), std::forward<Args>(args)...); 
    using D = alloc_deleter<Alloc>; 
    return std::unique_ptr<T, D>(p, D(a)); 
    } 
    catch (...) 
    { 
    AT::deallocate(a, p, 1); 
    throw; 
    } 
} 

int main() 
{ 
    std::allocator<int> a; 
    auto p = allocate_unique<int>(a, 0); 
    return *p; 
} 
+0

@LucDanton, tôi đã khôi phục bản chỉnh sửa của mình, tôi đã chọn từ chối thay vì hoàn trả một cách rõ ràng. 'allocate_shared' phải rebind anyway, vì vậy nó không quan trọng, nhưng ở đây không đúng. Nếu các thùng chứa có thể yêu cầu value_type chính xác thì có thể 'allocate_unique' impl của tôi :-) –

+0

Cảm ơn Jonathan. Tôi đã cân nhắc các ghi chú ACCU của tôi thay vì viết mã nhiều gần đây nhưng tôi đã sử dụng mã này ở ba nơi mà không có sự cố, vì vậy nó tạm thời nhận được con dấu Hatcat phê duyệt. – hatcat

+0

@ whatcat, tuyệt, vui vì nó hoạt động. Cảm ơn bạn đã nói chuyện với sét tại ACCU, nó nhắc tôi nhớ tôi muốn chơi cách ly. –

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