来自Stackoverflow的回答,很清晰地讲解了enable_shared_from_this所解决的用其他方法无法解决的问题。
https://stackoverflow.com/questions/712279/what-is-the-usefulness-of-enable-shared-from-this
from Dr Dobbs article on weak pointers, I think this example is easier to understand (source: http://drdobbs.com/cpp/184402026):
...code like this won't work correctly:
int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);
Neither of the two shared_ptr objects knows about the other, so both will try to release the resource when they are destroyed. That usually leads to problems.
Similarly, if a member function needs a shared_ptr object that owns the object that it's being called on, it can't just create an object on the fly:
struct S
{
shared_ptr<S> dangerous()
{
return shared_ptr<S>(this); // don't do this!
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->dangerous();
return 0;
}
This code has the same problem as the earlier example, although in a more subtle form. When it is constructed, the shared_ptr object sp1 owns the newly allocated resource. The code inside the member function S::dangerous doesn't know about that shared_ptr object, so the shared_ptrobject that it returns is distinct from sp1. Copying the new shared_ptr object to sp2 doesn't help; when sp2 goes out of scope, it will release the resource, and when sp1 goes out of scope, it will release the resource again.
The way to avoid this problem is to use the class template enable_shared_from_this. The template takes one template type argument, which is the name of the class that defines the managed resource. That class must, in turn, be derived publicly from the template; like this:
struct S : enable_shared_from_this<S>
{
shared_ptr<S> not_dangerous()
{
return shared_from_this();
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->not_dangerous();
return 0;
}
When you do this, keep in mind that the object on which you call shared_from_this must be owned by a shared_ptr object. This won't work:
int main()
{
S *p = new S;
shared_ptr<S> sp2 = p->not_dangerous(); // don't do this
}
Notice:
1. The documentation states that shared_from_this() only works if at least one strong reference to the instance exists. And this means you can't use shared_from_this() in a constructor.
(quote from https://forum.libcinder.org/topic/solution-calling-shared-from-this-in-the-constructor)
2. ‘enable_shared_from_this’ requires the object be owned by a ‘shared_ptr’, either via a call to ‘make_shared’ or a ‘shared_ptr’ constructor. This requirement is unfortunately never checked: if the object is not owned by a ‘shared_ptr’ no compile-time, nor run-time error will be generated. The code ventures into the land of undefined behaviour.
(quote from https://mortoray.com/2013/08/02/safely-using-enable_shared_from_this/)
实践中何时使用shared_from_this
转自https://www.cnblogs.com/mkdym/p/4947296.html
异步编程时,我们在传入回调的时候,通常会想要其带上当前类对象的上下文,或者回调本身就是类成员函数,那这个工作自然非this指针莫属了,像这样:
void sock_sender::post_request_no_lock()
{
Request &req = requests_.front();
boost::asio::async_write(*sock_ptr_,
boost::asio::buffer(req.buf_ptr->get_content()),
boost::bind(&sock_sender::self_handler, this, _1, _2));
}
然而回调执行的时候并不一定对象还存在。为了确保对象的生命周期大于回调,我们可以使类继承自boost::enable_shared_from_this,然后回调的时候使用boost::bind传入shared_from_this()返回的智能指针。由于boost::bind保存的是参数的副本,bind构造的函数对象会一直持有一个当前类对象的智能指针而使得其引用计数不为0,这就确保了对象的生存周期大于回调中构造的函数对象的生命周期,像这样:
class sock_sender
: public boost::enable_shared_from_this<sock_sender>
{
//...
};
void sock_sender::post_request_no_lock()
{
Request &req = requests_.front();
boost::asio::async_write(*sock_ptr_,
boost::asio::buffer(req.buf_ptr->get_content()),
boost::bind(&sock_sender::self_handler, shared_from_this(), _1, _2));
}