enable_shared_from_this的用处

来自Stackoverflow的回答

--------转载信息------------ 
作者:wqfhenanxc 
来源:CSDN 
原文: https://blog.csdn.net/wqfhenanxc/article/details/80532931

很清晰地讲解了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/ )

void register_service( shared_ptr<service> );
 
class service : public enable_shared_from_this<service> {
public:
    void register() {
        register_service( shared_from_this() );
    }
}
 
//intended use
auto good = make_shared<service>();
good->register();
 
//bad use
service bad;
bad.register(); //undefined behaviour on 'shared_from_this'
 
//also bad
auto pbad = new service();
pbad->register();

实践中何时使用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));
}

一些思考

在陈硕的《linux多线程服务端编程》这本书里,提到过 bind对象参数 是this指针的情况,可以通过enable_shared_from_this 来保证生命周期的问题,但是也同时提到了,这种情况下延长了对象的生命周期,使得其不短于绑得的std::function对象

书里边介绍了弱回调技术,针对“如果对象还活着,就调用它的回调函数,否则忽略之”这种情况。把weak_ptr绑到function对象里,这样对象的生命周期不会被延长,然后回调的时候先尝试提升为 shared_ptr,如果提升成功,就说明接受回调的对象还健在,那么就执行回调函数,如果提升失败,就不必劳神了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值