I have a function which takes a shared_ptr<MyClass>
. In some member function memfun
of MyClass
, I need to pass this
to that function. But if I write
void MyClass:memfun() { func(shared_ptr<MyClass>(this)) }
I am assuming that after the call has ended the reference count will reach 0 and this
will be attempted to be destroyed, which is bad.
Then I remembered that there this class enable_shared_from_this
with the function shared_from_this
.
So now I am going to use the following:
class MyClass: public enable_shared_from_this<MyClass> { void MyClass:memfun() { func(shared_from_this()); } };
Questions are:
1) Is is absolutely impossible to use the functionality without deriving from enable_shared_from_this
?
2) Does deriving from enable_shared_from_this
mean that calling memfun on an object with automatic storage duration will result in something bad? E.g.
int main() { MyClass m; //is this OK? m.memfun(); // what about this? }
3) If I derive from MyClass, will the enable_shared_from_this functionality be correctly inherited or do I need to derive again? That is,
class MyCoolClass: public Myclass { void someCoolMember { someCoolFuncTakingSharedPtrToMyCoolClass(shared_from_this()); } }
Is this OK? Or correct is the following?
class MyCoolClass: public Myclass, public enable_shared_from_this<MyCoolClass> { void someCoolMember { someCoolFuncTakingSharedPtrToMyCoolClass(enable_shared_from_this<MyCoolClass>::shared_from_this()); } }
Thanks very much in advance.
The mechanism of enable_shared_from_this , combined with the inherent thread safety of std::shared_ptr reference counting, enable us to ensure that the Client object cannot be destructed while the callback code is accessing its internal members.
The shared_from_this function searches for the existing control block rather than creating a new one. The simplest way to control this is to make the constructor private. Objects will be created using a static factory function that passes arguments to the private constructor.
std::enable_shared_from_this is a standard solution that enables a shared_ptr managed object to acquire a shared_ptr to itself on demand. A class T that publicly inherits an std::enable_shared_from_this<T> encapsulates a std::weak_ptr<T> to itself that can be converted to a std::shared_ptr<T> when needed.
Purpose. The header <boost/enable_shared_from_this. hpp> defines the class template enable_shared_from_this. It is used as a base class that allows a shared_ptr to the current object to be obtained from within a member function.
1) It depends on what you mean by "do this" as to whether or not you can. You can always construct a shared_ptr
from a raw pointer such as this
, but it won't share the reference count with another shared_ptr
instance that was separately constructed from a raw pointer. You will thus need to use a custom deleter on one or other instance to avoid double deletions, but unless you take great care then you may end up with dangling shared_ptr
instances due to the object being deleted through one, but still accessible from another.
shared_from_this
enables you to guarantee that if you have one shared_ptr
instance to your object then you can construct another without copying the first, and that these instances will share the reference count. You could achieve this by storing a weak_ptr
as a class member, and setting that value when you first allocate a shared_ptr
to your object.
2) Calling shared_from_this()
requires that there is at least one shared_ptr
instance already pointing to your object. If you use it on an automatic object without a shared_ptr
instance with a custom deleter then you will get bad stuff happening.
3) If you derive from your class then the enable_shared_from_this
functionality will give you a shared_ptr
to the base class (the one that derived from enable_shared_from_this
). You could then use static_pointer_cast
or dynamic_pointer_cast
to cast the result of shared_from_this()
to a pointer to the derived class.
The important question here is why does the function take the argument through a shared_ptr
. Does it store the pointer internally for later use? Does it only use it for the duration of the call? Why is the ownership diluted among the caller and the callee?
Some answers suggest that you provide a no-op deleter if you are going to pass a stack allocated object into the function, but if the function is actually storing the shared_ptr
for later use, it might be the case that by the time it gets around to it, the locally allocated object is no longer in the stack and you trigger UB. Having the no-op deleter shared_ptr
will allow the call, but the semantics will not be correct.
If the function does not store the shared_ptr
for later use, what was the design decision that led to that API? If you can change the function (and there is no impending reason), make it receive the argument by reference and you will have a friendlier interface that does not impose a shared_ptr
for no reason.
If at the end you determine that you can guarantee that the object in the stack will be alive for the whole duration of the process triggered by that function call, then and only then use the no-op deleter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With