我一直在努力用引用计数指针替换原始指针,这些指针只暴露底层的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;
}
Run Code Online (Sandbox Code Playgroud)
我看不出让这个返回智能指针的好方法.天真的方法会是这样的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 ); }
Run Code Online (Sandbox Code Playgroud)
编辑:感谢您的回复.我希望避免使用boost或tr1,但我认识到不使用经过良好测试的库通常是不明智的.我相当确定我所实现的与std :: auto_ptr 不相似,而是类似于tr1 :: shared_ptr,除了它只暴露内部指针的const版本并缺少官方版本中的一些功能.我真的想避免像Gian Paolo提出的那样的侵入式计划.我知道我的实现不是线程安全的,但这是一个单线程的应用程序.
| 归档时间: |
|
| 查看次数: |
1218 次 |
| 最近记录: |