C++ 智能指针,带有;这";在C++;
我一直致力于用引用计数指针替换原始指针,这些指针只公开基础指针的常量版本。我的目标是减少内存使用(以及不必要地构造和破坏复杂对象所花费的时间),而不让自己陷入任何代码都可以访问它不拥有的内存的情况。我知道引用计数的循环引用问题,但我的代码不应该造成这种情况 要求常量是可行的,因为在我使用的系统中,类通常不公开任何非常量成员,而不是修改对象,您必须对其调用一个方法,该方法返回修改后产生的新对象。这可能是一种设计模式,但我不知道它的名字 当我有一个方法返回指向其类型的对象(有时是对象本身)的指针时,我的问题就来了。以前看起来是这样的:C++ 智能指针,带有;这";在C++;,c++,this,smart-pointers,C++,This,Smart Pointers,我一直致力于用引用计数指针替换原始指针,这些指针只公开基础指针的常量版本。我的目标是减少内存使用(以及不必要地构造和破坏复杂对象所花费的时间),而不让自己陷入任何代码都可以访问它不拥有的内存的情况。我知道引用计数的循环引用问题,但我的代码不应该造成这种情况 要求常量是可行的,因为在我使用的系统中,类通常不公开任何非常量成员,而不是修改对象,您必须对其调用一个方法,该方法返回修改后产生的新对象。这可能是一种设计模式,但我不知道它的名字 当我有一个方法返回指向其类型的对象(有时是对象本身)的指针时,
Foo * Foo::GetAfterModification( const Modification & mod ) const
{
if( ChangesAnything( mod ) )
{
Foo * asdf = new Foo;
asdf.DoModification( mod );
return asdf;
}
else
return this;
}
我找不到一个好方法使这个返回成为一个智能指针。天真的方法类似于return CRcPtr(this)
,但这打破了所有权语义,因为我返回的内容和以前拥有该对象的人现在都认为他们拥有所有权,但彼此不了解。唯一安全的方法是返回CRcPtr(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 ); }
模板
类CRcPtr
{
公众:
显式CRcPtr(T*p_pBaldPtr)
{
m_pInternal=p_pBaldPtr;
m_i计数=新的无符号短(1);
}
CRcPtr(施工CRcPtr和p_其他)
{Acquire(p_Other);}
模板
显式CRcPtr(常量CRcPtr&p_It)
{
m_pInternal=动态铸造(p_It.m_pInternal);
如果(m_pInternal)
{
m_i计数=p_It.m_i计数;
(*m_i计数)+;
}
其他的
m_i计数=新的无符号短(1);
}
~CRcPtr()
{Release();}
CRcPtr和操作员=(常数CRcPtr和p_其他)
{
释放();
获取(p_其他);
}
常量T&运算符*()常量
{return*m_pInternal;}
常量T*运算符->()常量
{返回m_pInternal;}
常量T*get()常量
{返回m_pInternal;}
私人:
无效释放()
{
(*m_iCount)--;
如果(*m_iCount==0)
{
删除m_pInternal;
删除m_iCount;
m_pInternal=0;
m_i计数=0;
}
}
无效收购(const CRcPtr&p_其他)
{
m_pInternal=p_Other.m_pInternal;
m_iCount=p_Other.m_iCount;
(*m_i计数)+;
}
模板
朋友级CRcPtr;
T*m_pInternal;
无符号短*m_i计数;
};
模板
CRcPtrref\U cast(常数CRcPtr和p\U It)
{return CRcPtr(p_It);}
编辑:谢谢你的回复。我希望避免使用boost或tr1,但我认识到不使用经过良好测试的库通常是不明智的。我相当确信,我实现的与std::auto_ptr不相似,而是与tr1::shared_ptr相似,只是它只公开内部指针的const版本,并且缺少官方版本中的一些功能。我真的很想避免像吉安·保罗所提议的那种干扰性计划。我知道我的实现不是线程安全的,但这是一个单线程应用程序。看看Boost的源代码。如果您从
enable\u shared\u from\u this
派生一个类,那么您就可以调用shared\u from\u this()
成员函数来完成这类工作。就语义而言,不变性的好处在于您可以在对象、线程和,不必担心人们会改变你所依赖的价值观。只要你的重新计数方案是正确的,你就不必担心所有权问题(我没有读你的,但还是使用Boost)。正如Ferruccio所回避的那样,你需要某种形式的共享指针。也就是说,可以在多个对象之间共享(安全!)。实现此功能的一种方法是从实现实际引用计数的类派生所有对象(至少是用于共享指针的对象)。这样,实际指针本身携带当前计数,并且您可以在任意多个不同对象之间共享指针
您目前拥有的与std::auto_ptr非常相似,您在所有权方面也遇到了同样的问题。用谷歌搜索一下,你会发现一些有用的信息
请注意,共享指针还有其他复杂性:特别是在多线程环境中,引用计数必须是原子的,并且必须处理自分配,以避免增加内部计数,从而使对象永远不会被销毁
谷歌也是你的朋友。在C++中查找共享指针的信息,你会发现大量的信息。那是对记忆的浪费…还有什么选择呢?每个副本都需要能够递增和递减相同的计数器,因此我无法找到一种方法,使它们都没有指向它的指针。+1。我以前使用过boost::shared_ptr和shared_from_this,效果非常好