详解C++中shared_ptr的使用教程
shared_ptr是一种智能指针(smart pointer)。shared_ptr的作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。 总结下几个使用shared_ptr需要注意的问题: 一. 相互引用链 class C; class B : public std::enable_shared_from_this<B> { public: ~B(){ cout << "~B" << endl; } void SetPC(std::shared_ptr<C>& pc){ _pc = pc; } private: std::shared_ptr<C> _pc; }; class C : public std::enable_shared_from_this<C> { public: ~C(){ cout << "~C" << endl; } void SetPB(std::shared_ptr<B>& pb){ _pb = pb; } private: std::shared_ptr<B> _pb; }; int main() { std::shared_ptr<C> pc = std::make_shared<C>(); std::shared_ptr<B> pb = std::make_shared<B>(); pc->SetPB(pb); pb->SetPC(pc); return 0; } 上面的代码中,B和C均不能正确析构,正确的做法是,在B和C的释放函数,如Close中,将其包含的shared_ptr置空。这样才能解开引用链。 二. 自引用 class C : public std::enable_shared_from_this < C > { public: ~C() { std::cout << "~C" << std::endl; } int32_t Decode(const char* data,size_t) { return 0; } void SetDecoder(std::function<int32_t(const char*,size_t)> decoder) { _decoder = decoder; } private: std::function<int32_t(const char*,size_t)> _decoder; }; int main() { { std::shared_ptr<C> pc = std::make_shared<C>(); auto decoder = std::bind(&C::Decode,pc,std::placeholders::_1,std::placeholders::_2); pc->SetDecoder(decoder); } // C不能正确析构 因为存在自引用 return 0; } 上面的C类包含了一个function,该function通过std::bind引用了一个std::shared_ptr,所以_decoder其实包含了一个对shared_ptr的引用。导致C自引用了自身,不能正确析构。需要在C的Close之类的执行关闭函数中,将_decoder=nullptr,以解开这种自引用。 三. 类中传递 class Session : public std::enable_shared_from_this < Session > { public: ~Session() { std::cout << "~C" << std::endl; } void Start() { // 进行一些异步调用 // 如 _socket.async_connect(...,boost::bind(&Session::ConnectCompleted,this),boost::asio::placeholders::error,...) } void ConnectCompleted(const boost::system::err_code& err) { if(err) return; // ... 进行处理 // 如 _socket.async_read(...,boost::bind(&Session::ReadCompleted,...) } void Session::ReadComplete(const boost::system::error_code& err,size_t bytes_transferred) { if (err || bytes_transferred == 0) { DisConnect(); return; } // 处理数据 继续读 // ProcessData(); // _socket.async_read(...) } private: std::function<int32_t(const char*,size_t)> _decoder; }; int main() { { std::shared_ptr<Session> pc = std::make_shared<Session>(); pc->Start(); } return 0; } 上面Session,在调用Start时,调用了异步函数,并回调自身,如果在回调函数的 boost::bind 中 传入的是shared_from_this(),那么并无问题,shared_ptr将被一直传递下去,在网络处理正常时,Session将正常运行,即使main函数中已经没有它的引用,但是它靠boost::bind”活了下来”,boost::bind会保存传给它的shared_ptr,在调用函数时传入。当网络遇到错误时,函数直接返回。此时不再有新的bind为其”续命”。Session将被析构。
也就是说,成员函数并不属于对象,非静态数据成员才属于对象。 因此如下调用在编译期是合法的: ((A*)nullptr)->Func(); 而如果成员函数A::Func()没有访问A的非静态成员变量,这段代码甚至能正确运行,如: class Test { public: void Say() { std::cout << "Say Test" << std::endl; } void Set(int data) { _data = data; } private: int _data; }; int main() { // 运行成功 ((Test*)nullptr)->Say(); // 运行会崩掉,尝试访问空指针所指内存(_data) ((Test*)nullptr)->Set(1); return 0; } 正因为这种特性,有时候在成员函数中纠结半天,也不会注意到这个对象已经”不正常了”,被释放掉了。 四. shared_ptr 使用总结 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 【SSH 框架项目的搭建--简化版】使用注解代替xml中的<bean&
- JSONP跨域访问实现登录验证
- c# 配置文件App.config操作类库的方法
- org.xml.sax.SAXParseException: An invalid XML character
- ruby-on-rails – 限制has_many关系中关联数量的最佳实践?
- ruby-on-rails – 为什么Rails以UTC格式存储时间?
- ios – 使用AFNetworking上传多个图像
- c – 如果存储指针,std :: list比std :: vector更好吗?
- C malloc valgrind无效写入大小
- Oracle计算时间差为毫秒的实现代码