2010-12-30 36 views
12

khi đọc "Beyond the C++ Thư viện Tiêu chuẩn: An Introduction to Boost", tôi có một ví dụ rất thú vị:cách tăng :: shared_ptr hoạt động?

class A 
{ 
public: 
    virtual void sing()=0; 
protected: 
    virtual ~A() {}; 
}; 

class B : public A 
{ 
public: 
    virtual void sing() 
    { 
     std::cout << "Do re mi fa so la"<<std::endl;; 
    } 
}; 

và tôi làm một số xét nghiệm:

int main() 
{ 

//1 
std::auto_ptr<A> a(new B); //will not compile ,error: ‘virtual A::~A()’ is protected 

//2 
A *pa = new B; 
delete pa; //will not compile ,error: ‘virtual A::~A()’ is protected 
delete (dynamic_cast<B*>(pa)); //ok 

//3 
boost::shared_ptr<A> a(new B);//ok 

} 

những gì tôi cảm thấy rất tò mò đây cách shared_ptr hoạt động như thế nào? cách nó suy ra lớp dẫn xuất B?

Cảm ơn bạn đã giúp đỡ!

cảm ơn tất cả, tôi viết một mẫu đơn giản về cách ~ shared_ptr làm việc

class sp_counted_base 
{ 
public: 
    virtual ~sp_counted_base(){} 
}; 

template<typename T> 
class sp_counted_base_impl : public sp_counted_base 
{ 
public: 
    sp_counted_base_impl(T *t):t_(t){} 
    ~sp_counted_base_impl(){delete t_;} 
private: 
    T *t_; 
}; 


class shared_count 
{ 
public: 
    static int count_; 
    template<typename T> 
    shared_count(T *t): 
     t_(new sp_counted_base_impl<T>(t)) 
    { 
     count_ ++; 
    } 
    void release() 
    { 
     --count_; 
     if(0 == count_) delete t_; 
    } 
    ~shared_count() 
    { 
     release(); 
    } 
private: 
    sp_counted_base *t_; 
}; 
int shared_count::count_(0); 

template<typename T> 
class myautoptr 
{ 
public: 
    template<typename Y> 
    myautoptr(Y* y):sc_(y),t_(y){} 
    ~myautoptr(){ sc_.release();} 
private: 
    shared_count sc_; 
    T *t_; 
}; 

int main() 
{ 
    myautoptr<A> a(new B); 
} 

chìa khóa là:

  1. hàm mẫu xây dựng
  2. tài nguyên không bị xóa trong ~ shared_ptr, nó bị xóa bởi shared_count

Trả lời

10

Đáng ngạc nhiên, khóa ở đây không phải là boost::shared_ptr destructor mà là hàm khởi tạo của nó.

Nếu bạn nhìn vào boost/shared_ptr.hpp, bạn sẽ thấy rằng shared_ptr<T> không 'đơn giản' có một constructor mong đợi một T * nhưng:

template<class Y> 
explicit shared_ptr(Y * p); 

Trong //3 khi bạn xây dựng một boost::shared_ptr từ một B *, không chuyển đổi sang A * diễn ra và nội bộ shared_ptr được xây dựng với loại B thực tế. Sau khi hủy bỏ đối tượng, việc xóa xảy ra trên một con trỏ B (không phải thông qua một con trỏ lớp cơ sở).

+1

Về mặt kỹ thuật, nó thực hiện chuyển đổi từ B * sang A *. Tất cả các truy cập tiếp theo đến con trỏ sẽ sử dụng loại A *. Các hoạt động trên loại B là thông qua tính đa hình tiêu chuẩn (chúng đi qua A *). Ngoại lệ duy nhất là destructor, mà shared_ptr ghi nhớ thông qua cơ chế "deleter" (hoặc một số khái quát hóa). – nobar

3

Mẫu lớp shared_ptr có thành viên loại lớp shared_count, do đó có một thành viên của loại con trỏ tới lớp sp_counted_base. Mẫu hàm tạo cho lớp shared_count gán một con trỏ cho một cá thể của mẫu lớp sp_counted_impl_p cho thành viên này được tạo khuôn mẫu theo loại đối số hàm tạo, chứ không phải bởi các shared_ptr::value_type. sp_counted_base có chức năng thành viên ảo thuần túy dispose bị ghi đè bởi sp_counted_impl_p. Bởi vì sp_counted_impl_p biết loại B trong ví dụ của bạn, nó có thể xóa nó mà không truy cập vào trình phá hủy lớp cơ sở và vì nó sử dụng công văn ảo, loại được xác định khi chạy. Phương pháp này đòi hỏi sự kết hợp của đa hình tham số và subtype.

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