Tôi sẽ trả lời câu hỏi này (2 năm sau) bằng cách sử dụng shared_ptr rất đơn giản mà người dùng sẽ hiểu.
Đầu tiên tôi sẽ đến một vài lớp bên, shared_ptr_base, sp_counted_base sp_counted_impl, và check_deleter cuối cùng là một mẫu.
class sp_counted_base
{
public:
sp_counted_base() : refCount( 1 )
{
}
virtual ~sp_deleter_base() {};
virtual void destruct() = 0;
void incref(); // increases reference count
void decref(); // decreases refCount atomically and calls destruct if it hits zero
private:
long refCount; // in a real implementation use an atomic int
};
template< typename T > class sp_counted_impl : public sp_counted_base
{
public:
typedef function< void( T* ) > func_type;
void destruct()
{
func(ptr); // or is it (*func)(ptr); ?
delete this; // self-destructs after destroying its pointer
}
template< typename F >
sp_counted_impl( T* t, F f ) :
ptr( t ), func( f )
private:
T* ptr;
func_type func;
};
template< typename T > struct checked_deleter
{
public:
template< typename T > operator()( T* t )
{
size_t z = sizeof( T );
delete t;
}
};
class shared_ptr_base
{
private:
sp_counted_base * counter;
protected:
shared_ptr_base() : counter( 0 ) {}
explicit shared_ptr_base( sp_counter_base * c ) : counter( c ) {}
~shared_ptr_base()
{
if( counter )
counter->decref();
}
shared_ptr_base( shared_ptr_base const& other )
: counter( other.counter )
{
if( counter )
counter->addref();
}
shared_ptr_base& operator=( shared_ptr_base& const other )
{
shared_ptr_base temp( other );
std::swap( counter, temp.counter );
}
// other methods such as reset
};
Bây giờ tôi sẽ tạo hai hàm "miễn phí" được gọi là make_sp_counted_impl, nó sẽ trả về một con trỏ tới một hàm mới được tạo.
template< typename T, typename F >
sp_counted_impl<T> * make_sp_counted_impl( T* ptr, F func )
{
try
{
return new sp_counted_impl( ptr, func );
}
catch( ... ) // in case the new above fails
{
func( ptr ); // we have to clean up the pointer now and rethrow
throw;
}
}
template< typename T >
sp_counted_impl<T> * make_sp_counted_impl( T* ptr )
{
return make_sp_counted_impl( ptr, checked_deleter<T>() );
}
Ok, hai hàm này rất cần thiết cho những gì sẽ xảy ra tiếp theo khi bạn tạo shared_ptr thông qua chức năng templated.
template< typename T >
class shared_ptr : public shared_ptr_base
{
public:
template < typename U >
explicit shared_ptr( U * ptr ) :
shared_ptr_base( make_sp_counted_impl( ptr ) )
{
}
// implement the rest of shared_ptr, e.g. operator*, operator->
};
Lưu ý những gì xảy ra ở trên nếu T không có giá trị và U là lớp "kiểm tra" của bạn. Nó sẽ gọi make_sp_counted_impl () bằng một con trỏ tới U, không phải là một con trỏ tới T. Việc quản lý hủy diệt hoàn toàn được thực hiện thông qua đây. Lớp shared_ptr_base quản lý việc đếm tham chiếu liên quan đến sao chép và gán, v.v ... Chính lớp shared_ptr quản lý việc sử dụng an toàn các kiểu quá tải toán tử (->, * vv).
Do đó, mặc dù bạn có shared_ptr để bỏ trống, bên dưới bạn đang quản lý một con trỏ thuộc loại bạn đã chuyển sang mới. Lưu ý rằng nếu bạn chuyển đổi con trỏ của bạn thành một khoảng trống * trước khi đưa nó vào shared_ptr, nó sẽ không biên dịch được trên check_delete để bạn thực sự an toàn ở đó.