我将使用一种非常简单的shared_ptr实现来回答这个问题(2年后),让用户能够理解。
首先,我会介绍几个辅助类,shared_ptr_base,sp_counted_base,sp_counted_impl和checked_deleter,其中最后一个是一个模板。
class sp_counted_base
{
public:
sp_counted_base() : refCount( 1 )
{
}
virtual ~sp_deleter_base() {};
virtual void destruct() = 0;
void incref();
void decref();
private:
long refCount;
};
template< typename T > class sp_counted_impl : public sp_counted_base
{
public:
typedef function< void( T* ) > func_type;
void destruct()
{
func(ptr);
delete this;
}
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 );
}
};
现在我将创建两个名为make_sp_counted_impl的"自由函数",它将返回指向新创建的一个的指针。
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( ... )
{
func( ptr );
throw;
}
}
template< typename T >
sp_counted_impl<T> * make_sp_counted_impl( T* ptr )
{
return make_sp_counted_impl( ptr, checked_deleter<T>() );
}
好的,当您通过一个模板函数创建shared_ptr时,这两个函数对于接下来会发生什么是至关重要的。
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 ) )
{
}
};
请注意,如果 T 是 void 而 U 是你的“test”类,上面的内容会发生什么。它将使用指向 U 而不是指向 T 的指针调用 make_sp_counted_impl()。所有的销毁管理都通过此处完成。shared_ptr_base 类管理与复制和赋值等相关的引用计数。shared_ptr 类本身管理操作符重载(->、* 等)的类型安全使用。
因此,尽管您拥有一个指向 void 的 shared_ptr,在底层,您正在管理传递到 new 中的类型指针。请注意,如果在将指针放入 shared_ptr 之前将其转换为 void*,它将无法在 checked_delete 上编译,所以你实际上也是安全的。