weak_ptr 与 一个难发现的错误(循环依赖问题)笔记

推荐B站视频:7.weak_ptr与一个非常难发现的错误_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV18B4y187uL/?p=7&spm_id_from=pageDriver&vd_source=a934d7fc6f47698a29dac90a922ba5a3一、weak_ptr    

  • weak_ptr并不拥有所有权
  • 并不能调用 -> 和 解引用*

准备好头文件和源文件:

  • cat.h
#ifndef CAT_H
#define CAT_H
#include <string>
#include <iostream>
class Cat{
public:
    Cat(std::string name);
    Cat() = default;
    ~Cat();
    void catInfo() const {
        std::cout<<"cat info name : "<<m_name<<std::endl;
    }
    std::string get_name() const{
        return m_name;
    }
    void set_cat_name(const std::string &name) {
        this->m_name = name;
    }
private:
    std::string m_name{"Mimi"};
};
#endif
  • cat.cpp
#include "cat.h"
Cat::Cat(std::string name) :m_name(name) {
    std::cout<<"Constructor of Cat : "<<m_name<<std::endl;
}
 
Cat::~Cat() {
    std::cout<<"Destructor of Cat"<<std::endl;
}
  • main.cpp
#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    std::shared_ptr<Cat> s_p_c1 = std::make_shared<Cat>("c1");
    std::weak_ptr<Cat> w_p_c1(s_p_c1);
    // use_count()
    cout<<"w_p_c1: " << w_p_c1.use_count() << endl; // 1
    cout<<"s_p_c1: " << s_p_c1.use_count() << endl; // 1
    // w_p_c1->catInfo();// error C2039: "catInfo": 不是 "std::weak_ptr<Cat>" 的成员

    std::shared_ptr<Cat> s_p_c2 = w_p_c1.lock();
    cout<<"w_p_c1: " << w_p_c1.use_count() << endl; // 2
    cout<<"s_p_c1: " << s_p_c1.use_count() << endl; // 2
    cout<<"s_p_c2: " << s_p_c2.use_count() << endl; // 2

    cout<<"over~"<<endl; 
    return 0;
}

二、一个难发现的错误(循环依赖问题

(1)weak_ptr   为什么会存在呢?

  • A类中有一个需求需要存储其他A类对象的信息
  • 如果使用shared_ptr,那么在销毁时会遇到循环依赖问题(Cyclic dependency problem)
  • 所以我们这里需要用一个不需要拥有所有权的指针来标记该同类对象
    • weak_ptr可以通过lock()函数来提升为shared_ptr(类型转换)

比方说我是一个Person,需要存储朋友的信息,需要用一个指针来指向另外一个人类,如果使用shared_ptr,那么在销毁时会遇到循环依赖问题(Cyclic dependency problem)。我在销毁的时候,我需要销毁我的朋友,我的朋友也需要销毁我,这样就出现了循环依赖问题。不知道谁先销毁,谁后销毁。所以我们这里需要用一个不需要拥有所有权的指针来标记该同类对象。

修改头文件cat.h

#ifndef CAT_H
#define CAT_H
#include <string>
#include <iostream>
#include <memory>
class Cat{
public:
    Cat(std::string name);
    Cat() = default;
    ~Cat();
    void catInfo() const {
        std::cout<<"cat info name : "<<m_name<<std::endl;
    }
    std::string get_name() const{
        return m_name;
    }
    void set_cat_name(const std::string &name) {
        this->m_name = name;
    }
    void set_friend(std::shared_ptr<Cat> cat) {   // 增加该函数
        m_friend = cat;
    }
private:
    std::string m_name{"Mimi"};
    std::shared_ptr<Cat> m_friend; // 增加该变量
};
#endif

main.cpp

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    std::shared_ptr<Cat> c3 = std::make_shared<Cat>("C3");
    std::shared_ptr<Cat> c4 = std::make_shared<Cat>("C4");
    cout<<"over~"<<endl; 
    return 0;
}

 执行结果,可以正常调用析构函数:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : C3
Constructor of Cat : C4
over~
Destructor of Cat
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

 可是如果让C3和C4互为朋友

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {
    std::shared_ptr<Cat> c3 = std::make_shared<Cat>("C3");
    std::shared_ptr<Cat> c4 = std::make_shared<Cat>("C4");

    c3->set_friend(c4);
    c4->set_friend(c3);
    cout<<"over~"<<endl; 
    return 0;
}

执行结果,发现无法正常调用析构函数:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : C3
Constructor of Cat : C4
over~
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

 (2)解决方案:将头文件的m_friendshared_ptr修改成weak_ptr即可

std::shared_ptr<Cat> m_friend; 
        ||
        ||  (修改成这样)
        ||
std::weak_ptr<Cat> m_friend; 

执行结果,发现可以正常调用析构函数:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : C3
Constructor of Cat : C4
over~
Destructor of Cat
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

相关推荐

  1. Spring循环依赖问题如何解决

    2024-01-26 19:18:02       35 阅读
  2. Spring 怎么解决循环依赖问题

    2024-01-26 19:18:02       29 阅读
  3. Spring解决循环依赖问题四种方法

    2024-01-26 19:18:02       21 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-26 19:18:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-26 19:18:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-26 19:18:02       82 阅读
  4. Python语言-面向对象

    2024-01-26 19:18:02       91 阅读

热门阅读

  1. C++实现模版模式 + 创建者模式的demo

    2024-01-26 19:18:02       50 阅读
  2. ffmpeg 实用命令 -- 设置预览图

    2024-01-26 19:18:02       52 阅读
  3. 每日OJ题_算法_二分查找③_力扣69. x 的平方根

    2024-01-26 19:18:02       58 阅读
  4. IDEA使用快捷键提炼函数(Extract Method)

    2024-01-26 19:18:02       49 阅读
  5. 字符串随机生成工具(开源)-Kimen(奇门)

    2024-01-26 19:18:02       48 阅读