繁体   English   中英

C ++中带有“ this”的智能指针

[英]Smart Pointers with “this” in C++

我一直在努力用引用计数的指针替换原始指针,该引用计数的指针仅暴露基础指针的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 ) ) ,但这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)提出的那种侵入性计划。 我知道我的实现不是线程安全的,但这是一个单线程应用程序。

看一下Boost 共享指针的来源。 如果从enable_shared_from_this<T>派生一个类,则可以调用enable_shared_from_this<T> shared_from_this()成员函数来执行此类操作。

就语义而言,不变性的伟大之处在于,您可以在对象,线程之间安全地共享数据,而不必担心人们会更改您依赖的值。 只要您的refcounting方案是正确的,您就不必担心所有权(我没有读过您的书,但是仍然使用Boost)。

正如Ferruccio所遗漏的那样,您需要某种形式的共享指针。 即,可以在多个对象之间共享(安全!)的对象。 进行此工作的一种方法是从实现实际引用计数的类派生所有对象(至少是那些打算与共享指针一起使用的对象)。 这样,实际的指针本身就会带有当前计数,并且您可以在任意多个对象之间共享指针。

当前您拥有的东西与std :: auto_ptr非常相似,并且您也遇到了所有权问题。 谷歌它,你应该找到一些有用的信息。

请注意,共享指针还会带来其他麻烦:特别是在多线程环境中,您的引用计数必须是原子的,并且必须处理自赋值以避免避免增加内部计数,从而永不破坏对象。

谷歌再次是您的朋友在这里。 只需在C ++中查找有关共享指针的信息,就会发现大量信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM