shared_from_this从构造函数调用

时间:2010-08-03 21:48:59

标签: c++ boost

我必须在创建容器时在容器中注册它。 没有智能指针,我会使用这样的东西:

a_class::a_class()
{
    register_somewhere(this);
}

使用智能指针我应该使用shared_from_this,但我不能在构造函数中使用它。

是否有 clean 方法来解决此问题?在类似的情况下你会做什么? 我正在考虑在创建之后引入一个init方法来调用,并将所有内容放在像这样的工厂函数中:

boost::shared_ptr<a_class> create_a()
{
    boost::shared_ptr<a_class> ptr(new a_class);
    ptr->init();
    return ptr;
}

在这种情况下是否可以遵循标准程序?

编辑:其实我的情况更复杂。我有2个对象,它们将保持彼此的指针。所以事实是我不是“注册”而是创建另一个对象(比如b_class),它需要this作为参数。 b_class接收this作为弱指针并存储它。

我添加这个是因为你给我设计建议(非常感谢),至少你可以知道我在做什么:

a_class::a_class()
{
    b = new b_class(this);
}

在我的程序中a_class是一个实体,b_class是表示状态的具体类之一(在构造函数中它只是起始状态)。 a_class需要指向当前状态的指针,b_class需要操纵实体。

a_class负责创建和销毁b_class实例,从而为它们维护一个shared_ptr,但b_class需要操作a_class,从而维护一个弱指针。 a_class实例“幸存”b_class个实例。

你建议在这种情况下避免使用智能指针吗?

7 个答案:

答案 0 :(得分:8)

  

a_class负责创建和销毁b_class个实例

...

  

a_class个实例“幸存”b_class个实例。

鉴于这两个事实,b_class实例在a_class实例作为a_class被销毁后可以尝试访问a_class实例时不应该存在危险instance负责销毁b_class个实例。

b_class可以只保存指向其关联的a_class实例的指针。原始指针不表示适用于这种情况的任何所有权。

在此示例中,a_class如何动态创建,聚合对象的一部分等无关紧要。无论创建a_class创建a_class管理其生命周期,就像b_class管理它实例化的class a_class; class b_class { public: b_class( a_class* a_ ) : a( a_ ) {} private: a_class* a; }; class a_class { public: a_class() : b( new b_class(this) ) {} private: boost::shared_ptr<b_class> b; }; 的生命周期。

E.g。

shared_ptr

注意,在这个玩具示例中,不需要class a_class { public: a_class() : b( this ) {} private: b_class b; }; ,对象成员也可以正常工作(假设您不复制实体类)。

{{1}}

答案 1 :(得分:5)

如果在构建期间绝对需要shared_ptr,最好有一个'init'函数。事实上,这是我能想到的唯一体面的方法。如果选择此路径,您可能应该有一个特殊的函数来创建此类型的对象,以确保调用init()

但是,根据您注册的内容,最好使用指向构造函数中对象的普通指针来提供您正在注册的任何对象,而不是shared_ptr。然后在析构函数中,您可以从管理器中取消注册该对象。

答案 2 :(得分:1)

为什么不使用http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/enable_shared_from_this.html

struct a_class : enable_shared_from_this<a_class> {
    a_class() {
        shared_ptr<a_class> ptr(this);
        register_somewhere(ptr);
    }
};

更新:这是一个完整的工作示例:

#include <stdio.h>
#include <boost/smart_ptr/enable_shared_from_this.hpp>

struct a_class;
boost::shared_ptr<a_class> pa;

void register_somewhere(boost::shared_ptr<a_class> p)
{
    pa = p;
};

struct a_class : boost::enable_shared_from_this<a_class> {
private:
    a_class() {
        printf("%s\n", __PRETTY_FUNCTION__);
        boost::shared_ptr<a_class> ptr(this);
        register_somewhere(ptr);
    }

public:
    ~a_class() {
        printf("%s\n", __PRETTY_FUNCTION__);
    }

    static boost::shared_ptr<a_class> create()
    {
        return (new a_class)->shared_from_this();
    }
};

int main()
{
    boost::shared_ptr<a_class> p(a_class::create());
}

注意工厂函数a_class :: create()。它的工作是确保只创建一个参考计数器。因为

boost::shared_ptr<a_class> p(new a_class);

创建两个引用计数器并双重删除对象。

答案 3 :(得分:1)

代码中 shared_ptr 不需要(正如您展示并解释一样)。 shared_ptr 适用于共享所有权。

你的b_class不拥有它a_class,实际上它甚至比它更长久,所以它应该只保留一个观察指针。

如果b_class是多态的且a_class的操作涉及更改其b_class指针,则应使用unique_ptr<b_class>

class a_class;
class b_class
{
  friend class a_class;
  a_class* mya;
  b_class(a_class*p)
  : mya(p) {}
public:
  virtual~b_class() {}   // required for unique_ptr<b_class> to work
  virtual void fiddle(); // do something to mya
};

class a_class
{
  std::unique_ptr<b_class> myb;
public:
  a_class()
  : myb(new b_class(this)) {}
  template<typename B>
  void change_myb()
  {
    myb.reset(new B(this));
  }
};

答案 4 :(得分:1)

我想出了一个帮助类来解决这个问题:

template <class Impl>
class ImmediatelySharedFromThis : public std::enable_shared_from_this<Impl> {
    typedef std::unique_ptr<void, std::function<void(void*)>> MallocGuard;
    typedef std::shared_ptr<Impl> SharedPtr;

    // disallow `new MyClass(...)`
    static void *operator new(size_t) = delete;
    static void *operator new[](size_t) = delete;
    static void operator delete[](void*) = delete;
protected:
    typedef std::pair<MallocGuard&, SharedPtr&> SharingCookie;

    ImmediatelySharedFromThis(SharingCookie cookie) {
        MallocGuard &ptr = cookie.first;
        SharedPtr &shared = cookie.second;
        // This single line contains the actual logic:
        shared.reset(reinterpret_cast<Impl*>(ptr.release()));
    }
public:
    // Create new instance and return a shared pointer to it.
    template <class ...Args>
    static SharedPtr create(Args &&...args) {
        // Make sure that the memory is free'd if ImmediatelySharedFromThis
        // is not the first base class, and the initialization
        // of another base class throws an exception.
        MallocGuard ptr(aligned_alloc(alignof(Impl), sizeof(Impl)), free);
        if (!ptr) {
            throw std::runtime_error("OOM");
        }

        SharedPtr result;
        ::new (ptr.get()) Impl(SharingCookie(ptr, result),
                               std::forward<Args>(args)...);
        return result;
    }

    static void operator delete(void *ptr) {
        free(ptr);
    }
};

class MyClass : public ImmediatelySharedFromThis<MyClass> {
    friend class ImmediatelySharedFromThis<MyClass>;

    MyClass(SharingCookie cookie, int some, int arguments) :
        ImmediatelySharedFromThis(cookie)
        // You can pass shared_from_this() to other base classes
    {
        // and you can use shared_from_this() in here, too.
    }
public:
    ....
};

...

std::shared_ptr<MyClass> obj = MyClass::create(47, 11); 

有点难看,但它确实有效。

答案 5 :(得分:0)

为此,我为shared_ptrweak_ptrenable_shared_from_this编写了自己的替代品。您可以在Sourceforge处查看。

与标准的enable_shared_from_this相比,它允许在没有辅助函数的构造函数和析构函数中调用shared_from_this() ,而不会产生空间开销。

注意:只有在临时创建时才允许在dtors中创建shared_ptr。也就是说,它们在dtor返回之前就被摧毁了。

答案 6 :(得分:0)

这是我的解决方案:

$http.get('/store-products.json').then(function(res){
    store.products = res.data;
});

(构造函数必须是公共的,才能从静态成员函数中调用,甚至是内部函数...)