简体   繁体   中英

Boost::shared_ptr instantiated using this

Consider the following case:

typedef boost::shared_ptr<B> BPtr;

class A
{
public:
    A() { b_ptr = BPtr(new B); }
    void a_func() { C::c_func(b_ptr); }
private:
    BPtr b_ptr;
}

class B
{
public:
    B() { b_ptr = BPtr(this); }
    void b_func() { C::c_func(b_ptr); }
private:
    BPtr b_ptr;
}

class C
{
public:
    static void c_func(BPtr b_ptr) { /*...*/ }
}

Is it ok to instantiate a shared_ptr with this ?
Is it ok to have two shared_ptr objects pointing to the same object? (eg A::b_ptr and B::b_ptr)
If one of these two gets out of scope - would B's instance be deleted?

I'm guessing I'm doing something fundamentally wrong.
I also thought about using dependency injection of b_ptr to B's constructor, but that too seems very wrong.

UPDATE:
To clarify - Both A and B need to use C::c_func. In turn, after some processing, C needs to call a callback function in B which I haven't specified above. Actually two cases are interesting:

  1. If there's a requirement that C won't be stateful - then it needs to receive BPtr both from A and from B as in the code above.
  2. If C is stateful and both A and B instantiate separate C instances, giving a BPtr in C's ctor.

Is it ok to instantiate a shared_ptr with this?

No, for at least several reasons:

  1. If you create a A or B object on the stack or statically, you end up with a shared_ptr "owning" the object created on the stack; when the object is destroyed, the shared_ptr destructor will be called, calling delete on the object, and only Bad Things Will Happen. Further, even if the object is created dynamically, you don't know for sure what the owner of your class may do with it: he may assign it to some other type of smart pointer like an auto_ptr , which has totally different semantics.

  2. You end up with a circular reference. For example, b_ptr owns the B object of which it is a member. You have to manually .reset() it in order for the B object to be destroyed.

You can get a shared_ptr from this by using enable_shared_from_this , but there are a lot of caveats: namely, you cannot call enable_shared_from_this in a constructor. Even so, you don't want to store a shared_ptr to an object inside of the object itself; it doesn't make any sense.

I'm guessing I'm doing something fundamentally wrong.

Yes, but since you haven't said what, exactly, you are trying to do, it's hard to say what you should be doing instead. You've only told us how you are trying to do this, not what you are trying to do in the first place.

I would recommend that you re-design to use std::enable_shared_from_this, eg

class B
{
   B();
public:
   std::shared_ptr<B> create() { return std::make_shared<B>(); } // Make sure B is allocated as shared_ptr inorder to ensure that shared_from_this() works.
};

However, if it's an API issue you have then you can do the following (although I don't recommend it).

void b_func() { C::c_func(BPtr(this, [](B*){})); } // Empty deleter. Nothing happens when shared_ptr goes out of scope. Note that c_func cannot take ownership of the pointer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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