사용자가 이해할 수있는 매우 간단한 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(); // 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
};
이제 새로 작성된 함수에 대한 포인터를 리턴하는 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( ... ) // 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>() );
}
자,이 두 함수는 템플릿 함수를 통해 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 ) )
{
}
// implement the rest of shared_ptr, e.g. operator*, operator->
};
T가 void이고 U가 "테스트"클래스 인 경우 위의 상황에 유의하십시오. T에 대한 포인터가 아닌 U에 대한 포인터와 함께 make_sp_counted_impl ()을 호출합니다. 파괴 관리는 모두 여기를 통해 수행됩니다. shared_ptr_base 클래스는 복사 및 할당 등과 관련된 참조 횟수를 관리합니다. shared_ptr 클래스 자체는 연산자 오버로드 (->, * 등)의 안전한 형식 사용을 관리합니다.
따라서 void_shared_ptr이 있지만 아래에 new로 전달한 유형의 포인터를 관리하고 있습니다. shared_ptr에 넣기 전에 포인터를 void *로 변환하면 checked_delete에서 컴파일되지 않으므로 실제로도 안전합니다.