#ifndef __CMN_SCOPED_PTR_H__
#define __CMN_SCOPED_PTR_H__
#include "cmnNonCopyable.h"
namespace utils
{
template < typename T, class Copyable = utils::noncopyable >
class scoped_ptr : Copyable
{
struct deleter_base
{
virtual void release() = 0;
} * Dt_;
template < typename _Dx >
class deleter
: public deleter_base
, Copyable
{
T* p_;
_Dx Dt_;
template < int v > struct int2type { enum { value = v }; };
template < typename _Type >
class is_mem_func_ptr
{
template < typename T0 >
struct is_mem_func_ptr_ { enum { res = 0 }; };
template < typename R, typename S >
struct is_mem_func_ptr_ < R (S::*)( ) > { enum { res = 1 }; };
public:
enum { res = is_mem_func_ptr_ < _Type >::res };
};
template < typename _DxiEx >
void deleter_internal_ex(_DxiEx Dt, int2type < 1 >)
{
(*p_.*Dt)();
}
template < typename _DxiEx >
void deleter_internal_ex(_DxiEx Dt, int2type < 0 >)
{
Dt(p_);
}
template < typename _Dxi >
void deleter_internal(_Dxi Dt)
{
deleter_internal_ex(Dt, int2type < is_mem_func_ptr < _Dxi >::res >( ));
}
template < typename _Ret >
void deleter_internal(_Ret (*Dt) ( ))
{
Dt();
}
public:
deleter(_Dx Dt, T* p)
: p_(p)
, Dt_(Dt)
{ }
virtual void release()
{
deleter_internal(Dt_);
}
};
public:
scoped_ptr()
: Dt_(NULL)
, array_(false)
, p_(NULL)
{ }
explicit scoped_ptr(T* p, bool array = false)
: Dt_(NULL)
, array_(array)
, p_(p)
{ }
template < typename _Dx >
scoped_ptr(T* p, _Dx Dt)
: Dt_(new deleter < _Dx > (Dt, p))
, array_(false)
, p_(NULL)
{ }
~scoped_ptr() { free(); }
operator T* () { return p_; }
T* operator->() { return p_; }
T* release()
{
T* p = p_;
p_ = NULL;
return p;
}
void reset(T* p = NULL)
{
if (p != p_)
{
free();
}
p_ = p;
}
T* get() { return p_; }
private:
void free()
{
if (NULL == Dt_)
{
if (array_)
{
delete [] p_;
}
else
{
delete p_;
}
}
else
{
Dt_->release();
}
}
private:
bool array_;
T* p_;
};
}
#ifdef SMALTI_NINJA
#define ninja_ptr utils::scoped_ptr
#endif
#endif
//-----------------------------------------------------------------------------
Тест:
#include "stdafx.h"
#include
#define SMALTI_NINJA
#include "cmnScopedPtr.h"
struct ITest
{
virtual void Release() volatile = 0;
};
class CTest : public ITest
{
virtual void Release() volatile { delete this; }
public:
static ITest* Create() { return new CTest; }
};
void Save(ITest* p) { }
class CSimple
{ };
int _tmain(int, _TCHAR* [])
{
ninja_ptr < int > pInt(new int);
ninja_ptr < CSimple > pSimple(new CSimple);
ninja_ptr < CSimple > pSimpleArray(new CSimple[100], true);
ninja_ptr < void > pMalloc(::malloc(100), &::free);
ninja_ptr < void > pAbort((void*)0, &::abort);
ninja_ptr < ITest > pRelease(CTest::Create(), &ITest::Release);
ninja_ptr < ITest > pAutoSave(CTest::Create(), Save);
return 0;
}
Недавно обнаружил баги, в основном с освобождением deleter-а, и reset. как появится время - исправлю. Но думаю суть идеи ясна, и вообще лучше посмотреть реализацию shared_ptr - там custom deleter без багов)
ReplyDelete