zoukankan      html  css  js  c++  java
  • C++ shared_ptr 循环引用泄露问题

    用一段代码来展示shared_ptr可能存在的内存泄露问题:

      1 /// 思路来源: 极客时间 https://time.geekbang.org/column/article/239580
      2 
      3 #include <iostream>
      4 
      5 using namespace std;
      6 
      7 class Node final
      8 {
      9 public:
     10     using this_type = Node;
     11     using shared_type = shared_ptr<this_type>;
     12 public:
     13     shared_type next; // 使用智能指针指向下一个节点
     14     string name;
     15 public:
     16     Node(string _name)
     17     {
     18         name = _name;
     19         cout << "Node constructor, name=" << name.c_str() << endl;
     20     }
     21 
     22     ~Node()
     23     {
     24         cout << "Node destructor, name=" << name.c_str() << endl;
     25     }
     26 };
     27 
     28 void LeakTest()
     29 {
     30     // 创建内存块 M_N1
     31     auto n1 = make_shared<Node>("n1");
     32     // 创建内存块 M_N2
     33     auto n2 = make_shared<Node>("n2");
     34     cout << "n1.ref=" << n1.use_count() << ", n2.ref=" << n2.use_count() << endl;
     35 
     36     n1->next = n2;
     37     cout << "n1.ref=" << n1.use_count() << ", n2.ref=" << n2.use_count() << endl;
     38 
     39     n2->next = n1;
     40     // M_N1.ref==2, M_N2.ref==2;
     41     cout << "n1.ref=" << n1.use_count() << ", n2.ref=" << n2.use_count() << endl;
     42     // 1. n1先销毁, 则M_N1的内存引用计数变为1, 还被n2->next引用
     43     // 2. n2销毁, 则M_N2的内存引用计数变为1, 还被n1->next引用
     44     // 3. 产生内存泄露
     45     
     46     /// 最终输出
     47     /// Node constructor, name=n1
     48     /// Node constructor, name = n2
     49     /// n1.ref = 1, n2.ref = 1
     50     /// n1.ref = 1, n2.ref = 2
     51     /// n1.ref = 2, n2.ref = 2
     52 }
     53 
     54 void NormalTestN1()
     55 {
     56     // 创建内存块 M_N1
     57     auto n1 = make_shared<Node>("n1");
     58     // 创建内存块 M_N2
     59     auto n2 = make_shared<Node>("n2");
     60     cout << "n1.ref=" << n1.use_count() << ", n2.ref=" << n2.use_count() << endl;
     61 
     62     n1->next = n2;
     63     // M_N1.ref==1, M_N2.ref==2;
     64     cout << "n1.ref=" << n1.use_count() << ", n2.ref=" << n2.use_count() << endl;
     65     // 1. n1先销毁, 则M_N1的内存引用计数变为0, 内存块M_N1需要销毁, 则此时会走到了n1的析构方法, n1析构时n1->next也被销毁, 此时n1->next(即内存块M_N2)引用计数变为1
     66     // 2. n2销毁, 则M_N2的内存引用计数变为0, 内存块M_N2需要销毁
     67     // 3. 无内存泄露
     68 
     69     /// 最终输出
     70     /// Node constructor, name=n1
     71     /// Node constructor, name = n2
     72     /// n1.ref = 1, n2.ref = 1
     73     /// n1.ref = 1, n2.ref = 2
     74     /// Node destructor, name = n1
     75     /// Node destructor, name = n2
     76 }
     77 
     78 void NormalTestN2()
     79 {
     80     // 创建内存块 M_N1
     81     auto n1 = make_shared<Node>("n1");
     82     // 创建内存块 M_N2
     83     auto n2 = make_shared<Node>("n2");
     84     cout << "n1.ref=" << n1.use_count() << ", n2.ref=" << n2.use_count() << endl;
     85 
     86     n2->next = n1;
     87     // M_N1.ref==1, M_N2.ref==2;
     88     cout << "n1.ref=" << n1.use_count() << ", n2.ref=" << n2.use_count() << endl;
     89     // 1. n1先销毁, 则M_N1的内存引用计数变为1
     90     // 2. n2销毁, 则M_N2的内存引用计数变为0, 内存块M_N2需要销毁, 则此时会走到了n2的析构方法, n2析构时n2->next也被销毁, 此时n2->next(即内存块M_N1)引用计数变为0
     91     // 3. 此时M_N1被销毁, 走到M_N1的析构函数
     92     // 4. 无内存泄露
     93 
     94     /// 最终输出
     95     /// Node constructor, name=n1
     96     /// Node constructor, name = n2
     97     /// n1.ref = 1, n2.ref = 1
     98     /// n1.ref = 2, n2.ref = 1
     99     /// Node destructor, name = n2
    100     /// Node destructor, name = n1
    101 }
    102 
    103 int main()
    104 {
    105     cout << "
    ==========LeakTest Begin==========" << endl;
    106     LeakTest();
    107     cout << "==========LeakTest End==========" << endl;
    108 
    109     cout << "
    ==========NormalTestN1 Begin==========" << endl;
    110     NormalTestN1();
    111     cout << "==========NormalTestN1 End==========" << endl;
    112 
    113     cout << "
    ==========NormalTestN2 Begin==========" << endl;
    114     NormalTestN2();
    115     cout << "==========NormalTestN2 End==========" << endl;
    116 
    117     return 0;
    118 }

    解决方案:使用weak_ptr

  • 相关阅读:
    Vim编辑器-Basic Visual Mode
    Vim编辑器-Windows
    Vim编辑器-Searching
    Vim编辑器-Text Blocks and Multiple Files
    Vim编辑器-Editing a Little Faster
    Vim编辑器-Basic Editing
    Android12系统源码分析:NativeTombstoneManager
    为什么色彩管理很重要?
    使用chrome调试代码时引入jquery
    抖音、微信超火中国红头像制作
  • 原文地址:https://www.cnblogs.com/qinruijie/p/13848012.html
Copyright © 2011-2022 走看看