智能指针share_ptr知识点
1、原理
智能指针share_ptr 的原理简单来说,就是**做引用计数,多一个引用就加1,少一个引用,就减去1,当引用计数为0,则认为没有人用了,就主动调用delete,完成对象释放
。**
2、关键变量
要实现智能指针,其关键变量为:
a) 指向托管对象的指针 T* m_ptrRef;
b) 引用计数变量的指针,即一个int指针 int m_count;
3、关键函数
//(a) 重载运算符= ->
//赋值运算符重载 =
template<typename T>
MySharedPtr<T>& MySharedPtr<T>::operator = (const MySharedPtr<T>& sp)
{
//若计数器为空,删除指针
if (m_ptrRef != nullptr)
{
release();
}
cout << "\t引用计数:" << sp.m_ptrRef->m_count << endl;
m_ptrRef = sp.m_ptrRef;
sp.m_ptrRef->m_count++;
return *this;
}
//重载运算符 -> m_ptrRef指向什么,本模板类也指向什么
template<typename T>
T* MySharedPtr<T>::operator->()
{
cout << "\t引用计数:" << m_ptrRef->m_count << endl;
return m_ptrRef->m_ptrRef;
}
//(b) 构造函数写两个,一个是参数为托管对象的指针,一个是参数为智能指针本身
// 初始化模板类对象,把托管对象的指针T带进来
template<typename T>
MySharedPtr<T>::MySharedPtr(T* ptr) :m_ptrRef(new PtrRefCountHelper<T>(ptr))
{
cout << "MySharedPtr()默认构造" << endl;
}
//参数为智能指针本身
template<typename T>
MySharedPtr<T>::MySharedPtr(const MySharedPtr<T>& sp)
{
cout << "\t引用计数:" << sp.m_ptrRef->m_count << endl;
//m_ptrRef浅拷贝给sp
m_ptrRef = sp.m_ptrRef;
//指针引用调用一次 m_count+1
sp.m_ptrRef->m_count++;
cout << "MySharedPtr()拷贝构造" << endl;
}
//(c) 引用计数加 函数主体
m_ptrRef = sp.m_ptrRef;
sp.m_ptrRef->m_count++;
//(d) 引用计数减release()函数,以及减到0时释放托管对象
//计数值--
template<typename T>
void MySharedPtr<T>::release()
{
cout << "\t引用计数:" << m_ptrRef->m_count << endl;
//析构一次执行一次 m_ptrRef->m_count-1 --在前,先-1再判定,
//当m_ptrRef->m_count == 0,释放指针对象
if (--m_ptrRef->m_count == 0)
{
delete m_ptrRef;
}
}
4、weak_ptr
环的问题:调用构造却不调用析构,造成内存泄露。
解决办法:使用 weak_ptr
weak_ptr
可以包含由 shared_ptr
管理的内存的引用,但 weak_ptr
不拥有这个内存,所以不能阻止 shared_ptr
释放内存。weak_ptr
离开作用域的时候不会销毁它指向的内存。
weak_ptr
的构造函数需要将一个 shared_ptr
或另一个 weak_ptr
作为参数。为了访问 weak_ptr
中保存的指针,需要将 weak_ptr
转换为 shared_ptr
。这有两种方法:
使用 weak_ptr
实例的 lock()
方法,这个方法返回一个 shared_ptr
。
将 weak_ptr
作为 shared_ptr
构造函数的参数,创建一个新的 shared_ptr
实例。
这两种情况下,如果 weak_ptr
关联的 shared_ptr
已经释放,新 shared_ptr
就是 nullptr
。
#include <iostream>
#include <memory>
std::weak_ptr<int> gw;
void f()
{
if (auto spt = gw.lock()) { // 使用之前必须复制到 shared_ptr
std::cout << *spt << "\n";
}
else {
std::cout << "gw is expired\n";
}
}
int main()
{
{
auto sp = std::make_shared<int>(42);
gw = sp;
f();
}
f();
}
5、小结
简单地讲,要想尽量减少管理内存的痛苦,那就尽量使用智能指针,消灭 new
,没有 new
就没有 delete
,没有 malloc()
就没有 free()
。