【问题标题】:shared_ptr and the this-pointershared_ptr 和 this 指针
【发布时间】:2011-06-19 19:47:07
【问题描述】:

好的,我开始使用共享指针并尽可能地传递共享指针。不再转换为原始指针。这很好用,除了在这种特定情况下:

假设我们有一个类也是另一个类的观察者,像这样:

class MyClass : public IObserver
   {
   public:
      MyClass (std::shared_ptr<SomeOtherClass> otherClass);
      void DoSomethingImportant();
   private:
      std::shared_ptr<SomeOtherClass> m_otherClass;
   };

这个类在我的应用中是这样使用的:

std::shared_ptr<MyClass> myInstance(new MyClass(otherInstance));
...
myInstance->DoSomethingImportant();

MyClass 获得一个指向另一个类的共享指针并将其存储在它的 m_otherClass 数据成员中。 在 DoSomethingImportant 方法中,MyClass 实例做了很多重要的事情,包括将自己注册为 m_otherClass 上的观察者,如下所示:

m_otherClass->registerObserver(this);

问题是registerObserver方法是这样定义的:

void registerObserver (std::shared_ptr 观察者);

它需要一个共享指针,但“this”是一个原始指针,而不是共享指针。

我看到了解决这个问题的三种方法:

  • 找到将普通指针转换为共享指针的技巧(请参阅问题convert pointer to shared_ptr),但该问题的答案仅建议复制共享指针,而不是关于如何实际将指针转换为共享指针.
  • 将指向我们自己的共享指针传递给方法,如下所示:“myInstance->DoSomethingImportant(myInstance);”这似乎有点愚蠢。
  • 将观察者部分放到一个单独的类中。这看起来有些矫枉过正,可能会使课程更难理解。

这个问题很明显,共享指针只是 C++ 的一个附加组件(我认为您在 C#(或一般的 .Net)和 Java 等其他语言/环境中没有同样的问题)。

关于如何处理这种情况的任何其他建议或技巧?

【问题讨论】:

  • 你不能用enable_shared_from_this吗? (见Getting a Boost shared_ptr from this
  • 谁在否决这个问题和所有答案?这真的是一个愚蠢的问题吗?
  • 我有时想知道...是否有些人不只是想获得徽章stackoverflow.com/badges/7/critic?userid=147192
  • 正如其他提到的 enable_shared_from_this 将解决您的问题。然而,这里没有人提到的一件事是你应该小心,因为你正在做的是创建一个循环引用(即,主题对其观察者有一个 shared_ptr,而观察者对其主题有一个 shared_ptr。很容易创建以下情况:主体和观察者都成为不朽的:-)。
  • @ds27680:你是对的,详细说明:只有所有者应该维护 shared_ptr,所有其他用户都应该使用weak_ptr。对于观察者,您可以选择:保留一个 shared_ptr 必须在注销时重置或保留一个 weak_ptr 并在不再有效时清理。

标签: c++ this this-pointer shared-ptr


【解决方案1】:

您需要的可能是enable_shared_from_thisshared_from_this 设施。文档是here

请注意,在构造函数完全完成并且对象已被另一个 shared_ptr 拥有之前,您不能使用 shared_from_this

struct test : boost::enabled_shared_from_this<test>
{
    test() {
       // shared_from_this(this); // error, still not owned by another shared_ptr
    }
    boost::shared_ptr<test> shared() {
       return shared_from_this(this);
    }
};
int main() {
   test * t = new test;
   // boost::shared_ptr<test> p = t->shared(); // error, not yet owned by other shared_ptr
   boost::shared_ptr<test> owner( t ); 
   boost::shared_ptr<test> p = t->shared();     // [*] ok, "owner" owns the object
}

[*] 这部分例子很傻,你可以把所有者复制到 p 中,而不是调用方法。在test 方法中调用shared_from_this 时,它只是用来说明什么时候可以调用。

【讨论】:

  • 这确实是我正在寻找的。 C++0x shared_ptr 有类似的解决方案吗? (我使用的是 Visual Studio 2010,而不是使用 Boost)你知道对内存占用的影响吗?它是否存储了一个指向自身的共享指针或者它是如何工作的?
  • 找到了,在Visual Studio 2010中确实有一个enable_shared_from_this。谢谢。
  • boost 和即将推出的标准库非常相似,如果不完全相同的话。这适用于智能指针(scoped_ptr 存在于 boost 中,但已从标准中删除)和线程(有关操作语义的一些细节已从原始 boost::thread 中更改...)
【解决方案2】:

对于观察者模式,被观察对象并不拥有观察者的所有权,为什么不直接使用原始指针呢?观察者的生命周期应该由观察者自己控制。

通过使用 enable_shared_from_this,您可以为观察者及其观察对象引入循环依赖。这意味着如果不明确删除,资源将永远不会被释放。

【讨论】:

    【解决方案3】:

    如何将构造函数设为私有并使用这样的静态构造方法:

    class MyClass : public IObserver
       {
       public:
          static std::shared_ptr<MyClass> createObserver(std::shared_ptr<SomeOtherClass> otherClass);
          void DoSomethingImportant();
       private:
          MyClass (std::shared_ptr<SomeOtherClass> otherClass);
          std::shared_ptr<SomeOtherClass> m_otherClass;
       };
    

    然后您可以在静态方法中干净地实例化观察者,而完全不必担心 this 指针。

    【讨论】:

    • 这假设观察者(实际上:所有观察者)需要在构建时附加(这并不总是需要)。还有错字:您可能打算将 createObserver 方法设为静态。
    【解决方案4】:


    您可以将注册步骤移到单独的方法中吗? :

    shared_ptr<SomeOtherClass> other(new SomeOtherClass());
    shared_ptr<MyClass> my(new MyClass());
    // register myself to the observer  
    other->registerObserver(my);
    my->DoSomethingImportant();
    

    一个好的观察者模式设计可以用 boost::signal 和 boost::bind 来实现 图书馆。我鼓励你看看。

    最好的问候,
    马辛

    【讨论】:

      猜你喜欢
      • 2014-04-07
      • 2017-06-09
      • 1970-01-01
      • 2012-09-07
      • 2023-03-03
      • 2020-07-10
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      相关资源
      最近更新 更多