推荐B站视频:7.weak_ptr与一个非常难发现的错误_哔哩哔哩_bilibilihttps://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_friend的shared_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>