我一直致力于用引用计数指针替换原始指针,这些指针仅公开底层指针的 const 版本。我的目标是减少内存使用(以及不必要地构造和破坏复杂对象所花费的时间),而不会让自己陷入任何代码都可以访问它不拥有的内存的情况。我知道引用计数的循环引用问题,但我的代码不应该造成这种情况。
要求 const-ness 是可行的,因为我使用的系统中类通常不公开非 const 成员,而不是更改对象,您必须在其上调用一个方法,该方法返回由更改产生的新对象。这可能是一种设计模式,但我不知道它的名称。
当我有一个方法返回指向其类型对象的指针时,我的问题就出现了,有时它本身就是。以前它看起来像这样:
Foo * Foo::GetAfterModification( const Modification & mod ) const
{
if( ChangesAnything( mod ) )
{
Foo * asdf = new Foo;
asdf.DoModification( mod );
return asdf;
}
else
return this;
}
我看不到让它返回智能指针的好方法。天真的方法类似于return CRcPtr< Foo >( this )
,但这会破坏所有权语义,因为我返回的内容以及以前拥有该对象的人现在都认为他们拥有所有权但彼此不了解。唯一安全的做法是return CRcPtr< Foo >( new Foo( *this ) )
,但这违背了我限制不必要的内存使用的意图。
有没有办法在不分配任何额外内存的情况下安全地返回智能指针?我的怀疑是没有。如果有,如果对象已在堆栈上分配,它将如何工作? 这个问题似乎相关,但并不相同,因为他可以让他的函数将原始指针作为参数,并且因为他使用的是 boost 库。
作为参考,我的自制智能指针实现如下。我相信它可能会更强大,但它比依赖于任何地方都可用的 boost 或 tr1 更便携,并且在这个问题之前它对我来说效果很好。
template <class T>
class CRcPtr
{
public:
explicit CRcPtr( T * p_pBaldPtr )
{
m_pInternal = p_pBaldPtr;
m_iCount = new unsigned short( 1 );
}
CRcPtr( const CRcPtr & p_Other )
{ Acquire( p_Other ); }
template <class U>
explicit CRcPtr( const CRcPtr< U > & p_It )
{
m_pInternal = dynamic_cast< T * >( p_It.m_pInternal );
if( m_pInternal )
{
m_iCount = p_It.m_iCount;
(*m_iCount)++;
}
else
m_iCount = new unsigned short( 1 );
}
~CRcPtr()
{ Release(); }
CRcPtr & operator=( const CRcPtr & p_Other )
{
Release();
Acquire( p_Other );
}
const T & operator*() const
{ return *m_pInternal; }
const T * operator->() const
{ return m_pInternal; }
const T * get() const
{ return m_pInternal; }
private:
void Release()
{
(*m_iCount)--;
if( *m_iCount == 0 )
{
delete m_pInternal;
delete m_iCount;
m_pInternal = 0;
m_iCount = 0;
}
}
void Acquire( const CRcPtr & p_Other )
{
m_pInternal = p_Other.m_pInternal;
m_iCount = p_Other.m_iCount;
(*m_iCount)++;
}
template <class U>
friend class CRcPtr;
T * m_pInternal;
unsigned short * m_iCount;
};
template <class U, class T>
CRcPtr< U > ref_cast( const CRcPtr< T > & p_It )
{ return CRcPtr< U >( p_It ); }
编辑:感谢您的回复。我希望避免使用 boost 或 tr1,但我认识到不使用经过良好测试的库通常是不明智的。我相当确定我所实现的与 std::auto_ptr不相似,而是与 tr1::shared_ptr 相似,只是它只公开了内部指针的 const 版本并且缺少正式版本中的一些功能。我真的很想避免像 Gian Paolo 提出的那种侵入式方案。我知道我的实现不是线程安全的,但这是一个单线程应用程序。