1. 几种智能指针

1. auto_ptr: c++11中推荐不使用他(放弃)

2. shared_ptr: 拥有共享对象所有权语义的智能指针

3. unique_ptr: 拥有独有对象所有权语义的智能指针

4. weaked_ptr: 到 std::shared_ptr 所管理对象的弱引用

1.1 weak_ptr

参考:https://zh.cppreference.com/w/cpp/memory/weak_ptr

  • std::weak_ptr 是一种智能指针,它对被 std::shared_ptr 管理的对象存在 非拥有性(“弱”)引用。在访问所引用的对象前必须 先转换为 std::shared_ptr。

  • std::weak_ptr 用来 表达临时所有权的概念

    • 当某个对象只有存在时才需要被访问,而且随时可能被他人删除时,可以使用 std::weak_ptr 来跟踪该对象。

    • 需要获得临时所有权时,则将其转换为 std::shared_ptr,此时如果原来的 std::shared_ptr被销毁,则该对象的生命期将被延长至这个临时的 std::shared_ptr 同样被销毁为止。

  • std::weak_ptr 的另一用法是:打断 std::shared_ptr 所管理的对象组成的环状引用。(打破shared_ptr的循环引用)

    • 若这种环被孤立(例如无指向环中的外部共享指针),则 shared_ptr 引用计数无法抵达零,而内存被泄露。

    • 能令环中的指针之一为弱指针以避免此情况。

循环引用的问题:该被调用的析构函数没有被调用

#include <iostream>
#include <memory>
using namespace std;class Parent;
typedef std::shared_ptr<Parent> ParentPtr;class Child
{
public:ParentPtr father;Child() {cout << "hello Child" << endl;}~Child() {cout << "bye Child\n";}
};typedef std::shared_ptr<Child> ChildPtr;class Parent {
public:ChildPtr son;Parent() {cout << "hello parent\n";}~Parent() {cout << "bye Parent\n";}
};void testParentAndChild()
{ParentPtr p(new Parent());ChildPtr c(new Child());p->son = c;c->father = p;
}int main()
{testParentAndChild();return 0;
}

问题:c只有调用p的析构的时候,才能被释放。p只有调用c的析构的时候,才能被释放。。形成了循环引用,造成了内存泄露

因此,引入新的智能指针,weak_ptr

1.2 weak_ptr基本用法

一旦外部指向shared_ptr资源失效,那么weak_ptr管理的资源自动失效

#include <iostream>
#include <cassert>
#include <memory>
using namespace std;class Object
{
public:Object(int id) : m_id(id) {std::cout << "init obj " << m_id << std::endl;}    ~Object() {std::cout << "bye bye " << m_id << std::endl;}int id() const {return m_id;}
private:int m_id;
};void sharedPtrWithWeakPtr()
{typedef std::shared_ptr<Object> ObjectPtr;typedef weak_ptr<Object> WeakObjectPtr;ObjectPtr obj(new Object(1));// 一旦外部指向shared_ptr资源失效,那么weak_ptr管理的资源自动失效
    WeakObjectPtr weakObj2;           // 裸指针 WeakObjectPtr weakObj(obj);       // 指向shared_ptr指针
    WeakObjectPtr weakObj3(obj);   cout << "obj use count is " << obj.use_count() << endl;   // 1--尽管weak_ptr也指向obj,但他只是监听者,本身并不影响引用计数次数
    {// weak_ptr使用方法 // 外部至少还有一个shared_ptr来管理资源,同时p自己本身的资源 -- p.use_count >= 2 auto p = weakObj.lock();         // auto == ObjectPtrif (p) {cout << p.unique() << endl;  // 0 -- p.use_count() >= 2
        }else {}}// 不指向某份资源
//    obj.reset();
//    {
//        auto p = weakObj.lock();      // auto == ObjectPtr
//        if (p) {
//            assert(false);
//        }
//        else {
//            cout << "null" << endl;   // 如果调用reset,就会执行这句话
//        }
//    } // 此时, Object(1)已经失效 obj.reset(new Object(2)) ;{auto p = weakObj.lock();       // 返回值如果有效, 在外部必须有weakObj指向同一个资源 if (p) {assert(false);}else {cout << "null " << endl;   // null
        }}weakObj = obj;    // 又有效了 // 想知道weak_ptr有没有管理一份资源(外部有没有资源), 又不想生成一个shared_ptrif (weakObj.expired()) {// 资源过期了 -- true cout << "no ptr" << endl;}else {cout << "have resource\n";}
}int main()
{sharedPtrWithWeakPtr();return 0;}

1.3 解决类之间循环引用

一旦外部指向shared_ptr资源失效,那么weak_ptr管理的资源自动失效

#include <iostream>
#include <cassert>
#include <memory>
using namespace std;class Parent;
typedef std::shared_ptr<Parent> ParentPtr;
typedef std::weak_ptr<Parent> WeakParentPtr;class Child
{
public:WeakParentPtr father;                 // 只有一环换成 weak_ptr, 即可打破环
    Child() {cout << "hello Child" << endl;}~Child() {cout << "bye Child\n";}
};typedef std::shared_ptr<Child> ChildPtr;
typedef std::weak_ptr<Child> WeakChildPtr;class Parent {
public:ChildPtr son;                 Parent() {cout << "hello parent\n";}~Parent() {cout << "bye Parent\n";}
};void testParentAndChild()
{ParentPtr p(new Parent());ChildPtr c(new Child());p->son = c;            c->father = p;        cout << (c->father).use_count() << endl;cout << (p->son).use_count() << endl;
}int main()
{testParentAndChild();return 0;
}

析构函数成功调用, 注意析构顺序,谁是weak_ptr对象,就先析构谁。

1.4 用 enable_shared_from_this从this转换到shared_ptr

  • 类中函数接口需要一个本对象智能指针的const引用 (如何生成本对象的智能指针)

  • 用 enable_shared_from_this从this转换到shared_ptr  (使用CRTP来使用 本对象的智能指针)

主要代码:

handleChildAndParent(shared_from_this(), ps);

完整代码:

#include <iostream>
#include <cassert>
#include <memory>
using namespace std;class Parent;
typedef std::shared_ptr<Parent> ParentPtr;
typedef std::weak_ptr<Parent> WeakParentPtr;class Child : public std::enable_shared_from_this<Child>  // 奇异模板参数 CRTP
{
public:WeakParentPtr father;                 // 只有一环换成 weak_ptr, 即可打破环
    Child() {cout << "hello Child" << endl;}~Child() {cout << "bye Child\n";}void CheckRelation() {}
};typedef std::shared_ptr<Child> ChildPtr;
typedef std::weak_ptr<Child> WeakChildPtr;void handleChildAndParent(const ParentPtr& p, const ChildPtr& c);class Parent : public enable_shared_from_this<Parent> {
public:WeakChildPtr son;                 Parent() {cout << "hello parent\n";}~Parent() {cout << "bye Parent\n";}void CheckRelation() {auto ps = son.lock();if (ps) {//原理: 类中存在weak_ptr指针,通过一系列方式转换成 shared_ptr,然后传参 handleChildAndParent(shared_from_this(), ps);    // 使用CRTP来使用 本对象的指针 ★ ★ ★ ★
        }cout << "after call checkRelation\n";}
};void testParentAndChild()
{ParentPtr p(new Parent());ChildPtr c(new Child());p->son = c;            c->father = p;        cout << (c->father).use_count() << endl;cout << (p->son).use_count() << endl;p->CheckRelation();
}void handleChildAndParentRef(const Parent& p, const Child& c)
{auto cp = c.father.lock();auto pc = p.son.lock();if (cp.get() == &p && pc.get() == &c) {cout << "right relation" << endl;}else {cout << "oop !!!\n";}
}// const xxx&: 减少拷贝次数
void handleChildAndParent(const ParentPtr& p, const ChildPtr& c)
{auto cp = c->father.lock();auto pc = p->son.lock();if (cp == p && pc == c){cout << "right relation\n";}else {cout << "oop!!!\n";}
}int main()
{testParentAndChild();return 0;
}

 

转载于:https://www.cnblogs.com/douzujun/p/10803365.html

深入学习c++--智能指针(二) weak_ptr(打破shared_ptr循环引用)相关推荐

  1. C++ — 智能指针的简单实现以及循环引用问题

    http://blog.csdn.net/dawn_sf/article/details/70168930 智能指针 _________________________________________ ...

  2. 【C++11新特性】 C++11智能指针之weak_ptr

    http://blog.csdn.net/xiejingfa/article/details/50772571 原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/ar ...

  3. c++11新特性_【C++11新特性】 C++11智能指针之weak_ptr

    如题,我们今天要讲的是 C++11 引入的三种智能指针中的:weak_ptr. 在学习 weak_ptr 之前最好对 shared_ptr 有所了解.如果你还不知道 shared_ptr 是何物,可以 ...

  4. C++ 智能指针(二) std::unique_ptr

    C++ STL智能指针系列: C++ 智能指针(一) std::auto_ptr C++ 智能指针(二) std::unique_ptr C++ 智能指针(三) std::shared_ptr C++ ...

  5. C++11智能指针(unique_ptr、shared_ptr、weak_ptr)boost::scoped_ptr

    C++11智能指针(unique_ptr.shared_ptr.weak_ptr)_-码农小非-的专栏-CSDN博客_c++ shared_ptr weak_ptr 原创)智能指针拾遗 (原创)智能指 ...

  6. iOS开发笔记(二):block循环引用

    写这篇文章的缘由是第一次面试时被问到了block循环引用的问题,当时回答的不是很好,首先要明确的是,block是否用copy修饰决定不了循环引用的产生,在此再一次进行补强,有不对的地方还请多多指教. ...

  7. 智能指针(unique_ptr、shared_ptr、weak_ptr)

    主要参考链接:C++ 智能指针最佳实践&源码分析 参考链接:C++11 make_shared - 简书 智能指针在 C++11 标准中被引入真正的标准库(C++98 中引入的 auto_pt ...

  8. C++学习笔记——智能指针

    c++里不像java等语言设置了垃圾回收的功能,但是c++通过它的王牌指针实现了智能指针这一解决办法. 目录 异常 1.异常 2.异常的使用 3.异常的规则 4.异常安全 智能指针 概念 原理 aut ...

  9. C++智能指针:weak_ptr实现详解

    文章目录 weak_ptr描述 声明 作用 原理实现 函数成员使用 总结 weak_ptr描述 声明 头文件:<memory> 模版类:template <class T> c ...

最新文章

  1. fiddler 抓取winform wcf包
  2. mysql+where+且,MySQL WHERE
  3. asp.net中上传图片并生成小图片,自动添加水印的代码 .
  4. 手把手教你发布一个Python包
  5. JS制作常见通知信息(适用于手机通知信息和电脑通知信息)
  6. python3的flask出现UnicodeDecodeError UnicodeDecodeError
  7. config kubectl_Kubernetes(k8s)中文文档 kubectl config set-context_Kubernetes中文社区
  8. 干货 | Tomcat 连接数与线程池详解
  9. 鸿蒙思维和小央美,中心路汝南路站附近艺术培训
  10. unittest学习记录
  11. java mvc web_JavaWeb MVC
  12. Netty工作笔记0068---Protobuf机制简述
  13. 论文翻译:Two-phase Hair Image Synthesis by Self-Enhancing Generative Model
  14. java图片对比度调整
  15. window.print()
  16. 解决Win10系统使用暴风激活导致的劫持浏览器主页问题
  17. 汉王OCR6.0软件使用分享
  18. 篇16:Windows安装配置Nessus时遇到的一些问题说明
  19. java 运行一个程序的全部过程
  20. NumPy数据分析基础:数组形态转换转置操作一文详解

热门文章

  1. ubuntu 删除opencv4_ubuntu16.04 卸载重装Opencv
  2. C#如何获得屏幕宽度和高度
  3. linux 下载python命令_Linux下修改Python命令的方法示例(附代码)
  4. c语言注释符的作用有哪两种,C语言编程的注释符号是?
  5. 序列化和反序列化_PHP序列化和反序列化
  6. C语言怎么处理多位数,急~~~~~~C语言问题~~怎么把这个计算程序改成能计算多位整数? 爱问知识人...
  7. mysql x锁 u锁_讲解更新锁(U)与排它锁(X)的相关知识
  8. python语言是非开源语言_python是非开源语言吗
  9. 系统学习深度学习(三十三)--Prioritized Replay DQN
  10. 表情识别(六)--局部特征学习和Handcrafted特征结合