关于智能指针的补充1
- 1.share_ptr存在的问题
- 2.weak_ptr
- 2.1介绍
- 2.2weak_ptr 核心代码逻辑
1.share_ptr存在的问题
先看这样一段代码
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#include"smartptr.h"
struct ListNode
{
GXPYY::shared_ptr<ListNode> _next=nullptr;
GXPYY::shared_ptr<ListNode> _prev=nullptr;
int _val = 0;
~ListNode()
{
cout << "~ListNode()" << endl;
}
};
template<class T>
void test()
{
GXPYY::shared_ptr<ListNode>sp1(new ListNode);
GXPYY::shared_ptr<ListNode>sp2(new ListNode);
//sp1->_next = sp2;
//sp2->_prev = sp1;
}
int main()
{
test<ListNode>();
return 0;
}
上述的代码中我们定义了一个双向链表,但是没有链接结点,编译的时候正常运行,正常析构,并没有出现内存泄漏的情况。接下来我们尝试链接:
链接之后我们发现,出现了内存泄漏,函数的生命周期结束之后并没有进行析构变量,造成的原因是:引用循环(Reference cycles)
相互依赖,导致循环引用。
2.weak_ptr
2.1介绍
-
std::weak_ptr是C++标准库中的智能指针类型,用于解决std::shared_ptr可能出现的循环引用问题。它提供了一种非拥有(non-owning)的观测指针,允许观测被std::shared_ptr管理的对象,但不会增加引用计数。
-
std::weak_ptr的核心思想是通过弱引用(weak reference)来解决循环引用问题。当存在std::shared_ptr之间的循环引用时,循环中的对象无法被正常释放,因为它们的引用计数无法降为零。这时可以使用std::weak_ptr来打破循环引用,因为std::weak_ptr不会增加引用计数,也不会影响资源的生命周期。
-
使用std::weak_ptr需要配合std::shared_ptr一起使用,通过std::shared_ptr的构造函数或std::shared_ptr::weak_ptr成员函数来创建。通std::weak_ptr可以检查对象是否还存在,以及获取对对象的强引用(通过调用 std::weak_ptr::lock()返回一个有效的std::shared_ptr)。
-
当需要访问由std::weak_ptr观测的对象时,应该先使std::weak_ptr::lock()来获取对应的std::shared_ptr,然后再进行访问。如果std::weak_ptr观测的对象已经被销毁,则std::weak_ptr::lock()将返回一个空的std::shared_ptr,可以用于检查对象是否存在。
-
通过使用std::weak_ptr,可以避免循环引用导致的资源泄漏,同时提供了一种安全的方式来观测被std::shared_ptr管理的对象,而不影响资源的生命周期。
总的来说 weak_ptr只指向资源 但是不参与释放管理
我们简单实现一下weak_ptr
2.2weak_ptr 核心代码逻辑
- 代码
// 不参与指向资源的释放管理
template<class T>
class weak_ptr
{
public:
weak_ptr()
:_ptr(nullptr)
{}
weak_ptr( shared_ptr<T>& sp)
:_ptr(sp.get())
{}
weak_ptr<T>& operator=(const shared_ptr<T>& sp)
{
if (_ptr != sp.get())
{
_ptr = sp.get();
}
return *this;
}
// 像指针一样
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
public:
T* _ptr;
};
可以 看到 他是配合share_ptr使用的。
现在我们换成weak_ptr来重新编译下代码
- 代码
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#include"smartptr.h"
struct ListNode
{
GXPYY::weak_ptr<ListNode> _next;
GXPYY::weak_ptr<ListNode> _prev;
int _val = 0;
~ListNode()
{
cout << "~ListNode()" << endl;
}
};
template<class T>
void test()
{
GXPYY::shared_ptr<ListNode>sp1(new ListNode);
GXPYY::shared_ptr<ListNode>sp2(new ListNode);
sp1->_next = sp2;
sp2->_prev = sp1;
}
int main()
{
test<ListNode>();
return 0;
}
正常运行 解决了内存泄漏问题