智能指针小结


static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。 初始化的时候自动初始化为0

为什么使用智能指针:

因为使用new和detele存在内存所有权不清晰,容易产生不销毁和多销毁的情况,不同的智能指针提供的不同的析构函数,在调用函数结束以后会有不同的动作。

什么是内存所有权不清晰,有什么影响

  • 例子1
int* fun()
{
	int a = 3;
	return &a;
}
int main()
{
	int* P = fun();
}

例子1fun函数和main函数都有变量a存储区的所有权;

  • 例子2
int* fun()
{
	static int a = 3;
	return &a;
}
int main()
{
	int* P = fun();
}

这时候变量a存储与静态存储区,在程序终止的时候才释放;这时候fun函数和main函数都不具备变量a存储区的所有权;

share_ptr

每种智能指针都是以类模板的方式实现的,shared_ptr 也不例外。shared_ptr(其中 T 表示指针指向的具体数据类型)的定义位于头文件;引用计数机制是基于引用计数的共享内存解决方案

什么是引用计数

shared_ptr有默认的回收机制delete,但是也可以自定义回收机制。另外每当使用一次,引用计数就会加1,当本次引用循环结束,引用计数减一,当计数为0的时候就会触发回收机制。

默认的回收机制

 template< class Deleter >
shared_ptr( std::nullptr_t ptr, Deleter d );

shared_ptr管理的对象不需要额外使用delete进行内存释放,当shared_ptr引用计数为0
以后会调用默认的detele删除机制,

指定回收机制

#include<iostream>
#include<new>
#include<memory>
using namespace std;

void fun(int* x)
{
	cout << "fun is called" << endl;
	delete x;
}
int main()
{
	shared_ptr<int> ptr(new int(5),fun);//计数为零以后调用fun		、
	return 0;
}

自定义回收机制的应用

get

将shared_ptr< int>类型转换为int* 类型,相当于只拿出智能指针指向的储存区,并不拿出智能指针的计数值的储存;

  • 例子
shared_ptr<int> fun()
{
	shared_ptr<int> res(new int(100));
	return res;
}
int main()
{
	auto y = fun();
	cout << *y << endl; //100
	cout << typeid(y).name() << endl;//class std::shared_ptr<int>
	cout << *(y.get()) << endl;//100
	cout << typeid(y.get()).name() << endl;//int * __ptr64
	return 0;
}
  • 例子2
void fun(int* A)
{return;}
int main()
{
	shared_ptr<int> N(new int(3));
	fun(N);//不合法
	fun(N.get());
}

reset

把原始的资源释放,将新的资源关联上;把指针指向的原始资源释放,把新的内容放入这块内存;当该资源的计数为0时,reset才生效;如果不为零,就无效

make_shared

std::shared_ptr在实现的时候使用的refcount技术,因此内部会有一个计数器(控制块,用来管理数据)和一个指针,指向数据。因此在执行 std::shared_ptr< A> p2(new A) 的时候,首先会申请数据的内存,然后申请内控制块,因此是两次内存申请,而 std::make_shared< A>() 则是只执行一次内存申请,将数据和控制块的申请放到一起;

指向数组的share_ptr的定义

shared_ptr<T[]> A(new int[5]);  //c++17
auto A = make_shared<int[]>(5); //c++20

禁止使用detele销魂shared_ptr管理的对象

会发生重复释放的错误

shared_ptr<int> A(new int(3));
detele A.get();//经过这个语句以后,指针A指向的资源被释放,指针悬空指向一个没有被分配的对象;但是计数还在,计数减1,计数为零,又一次释放该资源

其他重复释放的错误

shared_ptr<int> A(new int(3));
shared_ptr<int> B(A.get());//把内存信息传给B,B拥有内存资源的所有权,且指针B计数为1;
程序结束的时候,B的计数减为0释放该内存;但是A也是指向这个内存空间,又一次释放;

unique_ptr

与shared_ptr的共享内存不同的是,unique_ptr是独占内存的解决方案,不支持复制但是支持移动,可以为unique_ptr指定回收逻辑

unique_ptr<int> y(new int(4));
unique_ptr<int> z = y;

这段代码报错,因为y独占内存,不能与指针z共享。与shared_ptr不同

资源所有权的移动,move方法

进行资源所有权转交

  1. 例子1
	unique_ptr<int> y(new int(4));
	unique_ptr<int> z = move(y);

move使得x放弃资源,将资源使用权移交与z
2. 例子2

#include<iostream>
#include<new>
#include<memory>
using namespace std;

unique_ptr<int> fun()
{
	unique_ptr<int> res = new int(3);
	return res;//隐形的转换
}
int main()
{
	unique_ptr<int> y = fun();//将开辟的资源通过一个临时对象进行转交
	return 0;
}

  1. 例子3
#include<iostream>
#include<new>
#include<vector>
#include<memory>
using namespace std;

int main()
{
	unique_ptr<int> y(new int(4));
	cout << y << endl;
	unique_ptr<int> z = move(y);
	cout << y << endl;
	cout << z << endl;
	return 0;
}

output:
0081E700
00000000
0081E700

make_unique

给unique_ptr指定回收逻辑,与shared-ptr不同。unique_ptr
模板中有两个参数,shared_ptr模板只有一个参数

#include<iostream>
#include<new>
#include<memory>
using namespace std;
void fun(int* ptr)
{
	
	delete ptr;
}
int main()
{
	shared_ptr<int> y(new int(3), fun));
	unique_ptr<int,decltype(fun)>  x(new int(3),fun);
	return 0;
}

weak_ptr

防止循环引用而引入的指针,基于shared_ptr构造

  • 例子1
#include<iostream>
#include<new>
#include<memory>
using namespace std;

struct Str
{
	shared_ptr<Str> m_nei;
	~Str()
	{
		cout << "Str is called" << endl;
	}
 
};
int main()
{
	shared_ptr<Str> x(new Str{});
	cout << x.use_count() << endl;
	shared_ptr<Str> y(new Str{});
	cout << y.use_count() << endl;
	x->m_nei = y;
	cout << y.use_count() << endl;
	//y->m_nei = x;
	//cout << x.use_count() << endl;
	return 0;
}

output:
1
1
2
Str is called
Str is called
  • 例子2
#include<iostream>
#include<new>
#include<memory>
using namespace std;

struct Str
{
	shared_ptr<Str> m_nei;
	~Str()//析构函数,当函数销毁以后来调用
	{
		cout << "Str is called" << endl;
	}
 
};
int main()
{
	shared_ptr<Str> x(new Str{});
	cout << x.use_count() << endl;
	shared_ptr<Str> y(new Str{});
	cout << y.use_count() << endl;
	x->m_nei = y;
	cout << y.use_count() << endl;
	y->m_nei = x;
	cout << x.use_count() << endl;
	return 0;
}
output:
1
1
2
2

并没有出现计数为零的情况,那么shared_ptr对象也就不会销毁进而执行析构函数所以这里就出现了 循环引用;这样导致没办法销毁内存。所以引入了waker_ptr;
因为例子2形成了一个环,所以导致计数不能减到0;

为了防止循环引用,使用weak_ptr;在初始化的时候不会增加相应资源的引用计数

  • 例子3
struct Str
{
	weak_ptr<Str> m_nei;
	~Str() { cout << "Str is called" << endl; }
};
int main()
{
	shared_ptr<Str> x(new Str{});
	shared_ptr<Str> y(new Str{});
	cout << x.use_count() << endl;//1
	cout << y.use_count() << endl;//1
	x->m_nei = y;
	y->m_nei = x;
	cout << x.use_count() << endl;//1
	cout << y.use_count() << endl;//1
	return 0;
}

初始化weak_ptr的时候,资源y的引用计数不变化;但是这样的话智能指针的计数优势就没了,因此引入了lock方法

lock

std::shared_ptr lock() const noexcept;
lock方法返回一个shared_ptr,所以说weak_ptr是由shared_ptr构成的

struct Str
{
	weak_ptr<Str> m_nei;
	~Str(){cout << "Str is called" << endl;}
};
int main()
{
	shared_ptr<Str> x(new Str{});
	{
		shared_ptr<Str> y(new Str{});
		x->m_nei = y;
		y->m_nei = x;
	}
	auto ptr = x->m_nei.lock();
	if (ptr)  {cout << "can access pointer" << endl;}
	else {cout << "cannot access pointer" << endl;}
	return 0;
}
output:
Str is called
cannot access pointer
Str is called
  • 例子2
struct Str
{
	weak_ptr<Str> m_nei;
	~Str(){cout << "Str is called" << endl;}
};
int main()
{
	shared_ptr<Str> x(new Str{});
    shared_ptr<Str> y(new Str{});
    x->m_nei = y;
    y->m_nei = x;
	auto ptr = x->m_nei.lock();
	if (ptr)  {cout << "can access pointer" << endl;}
	else {cout << "cannot access pointer" << endl;}
	return 0;
}

//output:
can access pointer
Str is called
Str is called
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星光技术人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值