2013-06-16 16 views
12

Tôi đã làm việc trên một cách để ngăn chặn người dùng sử dụng một lớp học mà không có con trỏ thông minh. Vì vậy, buộc họ phải có đối tượng được phân bổ và quản lý bởi con trỏ thông minh. Để có được kết quả như vậy, tôi đã thử như sau: Làm thế nào để ép buộc chỉ trình con trỏ thông minh cho một lớp học?

#include <memory> 
class A 
{ 
private : 
    ~A {} 
    // To force use of A only with std::unique_ptr 
    friend std::default_delete<A>; 
}; 

Công việc này khá tốt nếu bạn chỉ muốn sử dụng lớp học của bạn là có khả năng thao túng thể hiện của lớp học của bạn thông qua std::unique_ptr. Nhưng nó không hoạt động cho std::shared_ptr. Vì vậy, tôi muốn biết nếu bạn có bất kỳ ý tưởng để có được một hành vi như vậy. Giải pháp duy nhất mà tôi đã tìm thấy được làm những điều sau đây (sử dụng friend std::allocator_traits<A>; là unsufficient):

#include <memory> 
class A 
{ 
private : 
    ~A {} 
    // For std::shared_ptr use with g++ 
    friend __gnu_cxx::new_allocator<A>; 
}; 

Nhưng giải pháp này không phải là cầm tay. Có lẽ tôi đang làm điều đó một cách sai lầm.

+0

Nice giải pháp ... okay, điều này sẽ không làm việc cho STL nhưng tôi luôn luôn muốn điều này cho việc thực hiện SharedPtr của riêng tôi và điều này giải quyết vấn đề của tôi! – mmmmmmmm

Trả lời

17

Tạo một chức năng nhà máy bạn bè trả về std::unique_ptr<A> và làm cho lớp của bạn không có nhà thầu có thể truy cập. Nhưng làm destructor sẵn:

#include <memory> 

class A; 

template <class ...Args> 
std::unique_ptr<A> make_A(Args&& ...args); 

class A 
{ 
public: 
    ~A() = default; 
private : 
    A() = default; 
    A(const A&) = delete; 
    A& operator=(const A&) = delete; 

    template <class ...Args> 
    friend std::unique_ptr<A> make_A(Args&& ...args) 
    { 
     return std::unique_ptr<A>(new A(std::forward<Args>(args)...)); 
    } 
}; 

Bây giờ khách hàng của bạn rõ ràng có thể nhận được một unique_ptr<A>:

std::unique_ptr<A> p1 = make_A(); 

nhưng khách hàng của bạn có thể cũng giống như dễ dàng có được một shared_ptr<A>:

std::shared_ptr<A> p2 = make_A(); 

std::shared_ptr thể được xây dựng từ std::unique_ptr. Và nếu bạn có bất kỳ người dùng viết gợi ý thông minh, tất cả họ phải làm gì để được tương thích với hệ thống của bạn là tạo ra một constructor mà phải mất một std::unique_ptr, giống như std::shared_ptr có, và điều này là rất dễ dàng để làm:

template <class T> 
class my_smart_ptr 
{ 
    T* ptr_; 
public: 
    my_smart_ptr(std::unique_ptr<T> p) 
     : ptr_(p.release()) 
    { 
    } 
    // ... 
}; 
+1

Câu trả lời hay! Cảm ơn, đó là sạch hơn rất nhiều so với giải pháp của tôi. – Nemikolh

+4

Khi có nhiều lớp 'B',' C' v.v. với một giao diện chung cần các hàm nhà sản xuất 'make_B()', 'make_C()', tôi có xu hướng thích các mẫu thành viên công cộng tĩnh 'T :: make() '. Điều này làm cho nó dễ dàng hơn một chút để thiết lập một nhà máy toàn diện + lớp đăng ký, nơi mà các kiểu cụ thể 'make()' có thể được đăng ký từ một danh sách kiểu tại thời gian biên dịch. – TemplateRex

+0

@TemplateRex: Đồng ý. Đó là một quy ước đặt tên tốt cho các chức năng của nhà máy. –

0

Vì không có thuật ngữ chung "con trỏ thông minh" những gì bạn muốn là không thể.

Bạn có thể làm gì, đang hỗ trợ một số bộ con trỏ thông minh đã biết. Các giải pháp thông thường bắt đầu như của bạn, làm cho ctor hoặc dtor riêng, và thêm chức năng nhà máy. Điều đó có thể trả về cá thể được đóng gói với con trỏ thông minh mong muốn của bạn. Nếu bạn chỉ muốn hỗ trợ unique_ptr và shared_ptr, nó có hai chức năng của nhà máy, hầu như không quá nhiều. (lưu ý rằng các con trỏ cho phép buôn lậu ra con trỏ thô thông qua giao diện đơn giản để điều khiển không đầy đủ.)