shared_ptr:弱回调技术

shared_ptr:弱回调技术

分类: Linux多线程编程   287人阅读  评论(0)  收藏  举报

           场景:公司company存有公司员工的信息,现在给定一个查询接口,给定员工姓名在公司中查找若找到返回员工信息,若没有找到在公司录入这个员工信息。

     1 若简单在公司company中用一个容器保存staff信息,那么staff离职了需要清理容器否则staff信息一直存在。

     2 又涉及了对象生命周期的管理,想到shared_ptr/weak_ptr,那么company用weak_ptr管理员工对象,即容器存放weak_ptr,给定员工姓名找到相应的weak_ptr尝试提升这个weak_ptr,若提升成功则表明公司有这个员工,否则需要录入这个员工。这样即使员工离职了,公司只保存了一个weak_ptr对象。但是这还是存在内存泄露,毕竟离职的weak_ptr没用了。

      3 利用shared_ptr的订制析构功能:

            3.1 定制删除器:

 shared_ptr(Y *p, D d)的第一个参数是要被管理的指针,它的含义与其他构造函数的参数相同,而第二个删除器参数d则告诉shared_ptr在析构时不是使用delete在操作指针p,而要用d来操作,即把delete p 换成d(p);在这里删除器d可以是一个函数对象,也可以是一个函数指针,只要它能够像函数那样被调用,使得d(p)成立即可。对删除器的要求是它必须是可拷贝的,行为必须也像delete那样,不能抛出异常。有了删除器的概念,就可以用shared_ptr实现管理任意资源,只要这种资源提供了它自己的释放操作。

template<class Y,class D> shread_ptr::shared_ptr(Y* p,D d)

template<class Y,class D> shared_ptr::reset(Y* p,D d)//这里Y与shared_ptr本身的模板参数T可以不同,只要Y*能隐式转换为T*  //shared_ptr<T> x//x本身的模板参数T

           3.2 利用shared_ptr的订制析构功能,传入一个仿生函数或函数指针d在析构时不用delete而用d。结合2,weak_ptr提升为shared_ptr后若没有提升成功,则新建员工信息并用shared_ptr订制析构功能注册个回调函数d作为删除器,这个删除器不再简单的delete对象而是再执行一个将公司容器中相应的weak_ptr删除,这样解决了2的内存泄露问题

           3.3 3.2company中创建员工信息时,订制析构器是利用boost::bind(&DeleteCallback,this,_1)这里假设DeleteCallback是删除器,this是company的this指针。这就将company对象的this指针暴漏给了析构员工对象的删除器。假设company在员工对象前销毁,那么删除器持有那个this找谁呢?core dump了。

     4  前面3中出现的又是company的对象声明周期的问题,回到shared_ptr/weak_ptr管理对象声明周期的问题上,那么company也要用shared_ptr来管理。利用enable_shared_from_this可以将this指针转化为shared_ptr对象。那么company的生命期不会短于删除器。

      下面看代码:

[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<string>  
  3. #include<map>  
  4. #include<boost/shared_ptr.hpp>  
  5. #include<boost/weak_ptr.hpp>  
  6. #include<boost/bind.hpp>  
  7. #include<boost/enable_shared_from_this.hpp>  
  8. #include<boost/noncopyable.hpp>  
  9. using namespace std;  
  10. using namespace boost;  
  11. class company;//公司  
  12. class staff{//员工  
  13.     public:  
  14.         staff(string x):name(x){}  
  15.         void check(shared_ptr<company> x);//员工要查看公司所有员工信息  
  16.         string& key(){//员工标识符就是姓名  
  17.             return name;  
  18.         }  
  19.         ~staff(){  
  20.             cout<<"~staff "<<name<<endl;  
  21.         }  
  22.     private:  
  23.         string name;//员工姓名  
  24. };  
  25. class company :public boost::enable_shared_from_this<company>,boost::noncopyable//enable_shared_from_this使this指针变身为shared_ptr  
  26. {  
  27.     public:  
  28.         shared_ptr<staff> get(const string name){//给定一个员工姓名查找公司中是否有,若有则返回,否则创建一个新员工,注意这里不要返回临时对象的引用,shared_ptr对象就是一个普通的对象  
  29.             shared_ptr<staff> member;  
  30.             lock();//互斥量保护  
  31.             weak_ptr<staff>& wk_member=vec[name];//注意这里是引用方便修改  
  32.             member=wk_member.lock();//weak_ptr提升操作原子操作线程安全  
  33.             if(!member){  
  34.                 member.reset(new staff(name),boost::bind(&company::WeakDeleteCallback,boost::weak_ptr<company>(shared_from_this()),_1));//订制析构,当shared_ptr管理的对象析构时就执行订制的仿生函数  
  35.                 //这里解决了很多问题:1保证了员工会被销毁 2若只采用简单weak_ptr管理员工则会造成轻微内存泄露即weak_ptr本身在公司map里不会被清理 3采用shared_from_this解决了公司的this指针泄露,若公司先于员工倒闭,那么员工访问公司core dump。注意这里的弱回调技术是weak_ptr<company>  
  36.                 wk_member=member;  
  37.             }  
  38.             unlock();  
  39.             return member;  
  40.         }  
  41.         void traverse(){//遍历公司员工  
  42.             lock();  
  43.             for(map<string,weak_ptr<staff> >::iterator it=vec.begin();it!=vec.end();it++){  
  44.                 shared_ptr<staff> temp(it->second.lock());  
  45.                 if(temp)  
  46.                     temp->check(shared_from_this());//遍历时每个员工执行一个请求公司互斥锁的操作时死锁了  
  47.             }  
  48.             unlock();  
  49.         }  
  50.         void lock() const{//加锁  
  51.             pthread_mutex_lock(&mutex);  
  52.         }  
  53.         void unlock() const{//解锁  
  54.             pthread_mutex_unlock(&mutex);  
  55.         }  
  56.         company(){//shared_from_this()不要在构造函数中调用,在构造的时候还没有被shared_ptr接管  
  57.             pthread_mutex_init(&mutex,NULL);  
  58.         }  
  59.         ~company(){  
  60.             cout<<"~company"<<endl;  
  61.         }  
  62.     private:  
  63.         static void WeakDeleteCallback(const boost::weak_ptr<company>& Com,staff* member){//弱回调函数  
  64.             shared_ptr<company> Com_(Com.lock());  
  65.             if(Com_){  
  66.                 if(member){  
  67.                     Com_->remove(member);  
  68.                 }  
  69.             }  
  70.             delete member;//别忘了这句,这是delelte真正的操作,前面那几句相当于附加操作罢了  
  71.         }  
  72.         void remove(staff* member){  
  73.             if(member){  
  74.                 lock();  
  75.                 vec.erase(member->key());  
  76.                 unlock();  
  77.             }  
  78.         }  
  79.         mutable pthread_mutex_t mutex;  
  80.         map<string,weak_ptr<staff> > vec;  
  81. };  
  82. void staff::check(shared_ptr<company> x){//遍历员工时用互斥锁保护,然后员工又调用此函数去申请公司的互斥锁,死锁了  
  83.     x->lock();  
  84.     cout<<"Can I get there? I think I can't"<<endl;  
  85.     x->unlock();  
  86. }  
  87. void LongLifeCompany(){  
  88.     cout<<"LongLifeCompany"<<endl;  
  89.     shared_ptr<company> google(new company);  
  90.     {  
  91.         shared_ptr<staff> LiLei=google->get("LiLei");  
  92.         //LiLei在这里析构  
  93.     }  
  94.     //google在这里析构  
  95. }  
  96. void LongLifeStaff(){  
  97.     cout<<"LongLifeStaff"<<endl;  
  98.     shared_ptr<staff> HanMeimei;  
  99.     {  
  100.         shared_ptr<company> google(new company);  
  101.         HanMeimei=google->get("HanMeimei");  
  102.         //google->traverse();//若执行这句则死锁  
  103.     }  
  104. }  
  105. int main(){  
  106.     LongLifeCompany();  
  107.     LongLifeStaff();  
  108.     return 0;  
  109. }  

输出:

LongLifeCompany
~staff LiLei
~company
LongLifeStaff
~company
~staff HanMeimei


若执行了google->traverse()那句则输出是:

LongLifeCompany
~staff LiLei
~company
LongLifeStaff
^C                                             //死锁了,只好中断了....

最后说明:

      注意35行的 member.reset(new staff(name),boost::bind(&company::WeakDeleteCallback,boost::weak_ptr<company>(shared_from_this()),_1));这行代码信息量略大啊!weak_ptr<company>真正实现了弱回调:若对象还活着则执行相关操作,否则忽略之。即员工对象发现company对象已经不存在(通过weak_ptr提升判断)则不执行从company删除自己的信息。

     分析这个bind函数:执行bind对象的是shared_ptr计数为0要析构对象,此时传入订制析构时delte A换成d(p),参数 shared_ptr(Y *p, D d)中的p而这正是员工(A)staff对象。那么boost::function<void()> f=bind(&WeakDelteCallback,weak_ptr<company>(shared_from_this(),_1)处的_1就是调用时传入的第一个参数。假设调用时是f(p)其中p是第一个参数赋给_1的位置,实质是WeakDeleteCallback(const boost::weak_ptr<company>& Com,staff* member)//_1的位置换成了执行时的第一个参数。

我发现了个问题:没有#include<pthread.h>程序还是执行了,互斥锁还是管用了....这点似乎以前遇见过.....

该错误通常出现在尝试在一个const类型的ros消息指针上调用getMessage()函数时。由于该指针是const的,因此不能对其进行修改,而getMessage()函数是用于修改消息的非const函数,因此编译器会报错。 解决这个问题的方法是,使用boost::const_pointer_cast函数将const类型的指针转换为非const类型指针。具体步骤如下: 1. 在你的C++代码中包含以下头文件: ``` #include <ros/ros.h> #include <ros/console.h> #include <rosgraph_msgs/Log.h> #include <boost/shared_ptr.hpp> #include <boost/const_pointer_cast.hpp> ``` 2. 然后,创建一个ros::Subscriber对象来订阅rosout节点: ``` ros::Subscriber sub = nh.subscribe("/rosout", 1000, &callback); ``` 其中,"/rosout"是要订阅的rosout节点的话题名称,1000是消息队列的大小,callback是当接收到消息时要调用的回调函数。 3. 在回调函数中,将const类型的指针转换为非const类型指针,然后再使用getMessage()函数: ``` void callback(const boost::shared_ptr<const rosgraph_msgs::Log>& msg) { boost::shared_ptr<rosgraph_msgs::Log> nonconst_msg = boost::const_pointer_cast<rosgraph_msgs::Log>(msg); std::string message = nonconst_msg->getMessage(); ROS_INFO_STREAM("Message: " << message); } ``` 这样,你就可以在C++代码中使用getMessage()函数获取订阅的消息了。注意,使用const_pointer_cast函数进行类型转换时要非常小心,避免意外修改const指针所指向的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值