智能指针

1.前言

  在C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。
  动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极其困难的。有时会忘记释放内存,在这种情况下会产生内存泄露;有时在尚有指针引用内存的情况下就释放了它,在这种情况下就会产生引用非法内存的指针。
  为了更容易(同时也更安全)地使用动态内存,C++11标准库提供了两种智能指针(smart pointer)类型来管理动态对象。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指的对象。C++11标准库提供的这两种智能指针的区别在于管理底层指针的方式:shared_ptr允许多个指针指向同一个对象;unique_ptr则"独占"所指向的对象。C++11标准库还定义了一个名为weak_ptr的辅助类,它是一种弱引用,指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。智能指针是模板类而不是指针。类似vector,智能指针也是模板,当创建一个智能指针时,必须提供额外的信息即指针可以指向的类型。默认初始化的智能指针中保存着一个空指针。智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象。如果在一个条件判断中使用智能指针,效果就是检测它是否为空。

2.使用

2.1 初始化

1.通过一个指向堆上申请的空间的指针初始化(切记不要用栈上的指针,否则,当智能指针全部释放控制权(栈中的对象离开作用域本身就会析构一次),将会析构对象,导致出错)

int a = new int(100);

 std::shared_ptr ptr(a); //我们不能写成std::shared_ptr ptr = a;这样写错误

2.通过make_shared函数得到

std::shared_ptr<int> ptr1 = std::make_shared<int>(15);
std::shared_ptr<int> ptr1 = std::make_shared<int>(); //创建一个空指针

3.拷贝初始化

std::shared_ptr<int> ptr2(ptr1);

//std::shared_ptr<int> ptr2 = ptr1;这样赋值是错误的,只要是智能指针,这样直接用=赋值是有问题的必须std::shared_ptr<int> ptr2(ptr1);

2.2 检查 shared_ptr 对象的引用计数

ptr1.use_count();

2.3 reset函数

当智能指针调用了reset函数的时候,就不会再指向这个对象了,所以如果还有其它智能指针指向这个对象,那么另外一个智能指针的use_count()函数结果会减1

2.4 shared_ptr是一个伪指针

shared_ptr充当普通指针,我们可以将*->与 shared_ptr 对象一起使用,也可以像其他 shared_ptr 对象一样进行比较;

3.完整示例

#include <iostream>
#include  <memory> // 需要包含这个头文件

int main()
{
	// 使用 make_shared 创建空对象
	std::shared_ptr<int> p1 = std::make_shared<int>();
	*p1 = 78;
	std::cout << "p1 = " << *p1 << std::endl; // 输出78

	// 打印引用个数:1
	std::cout << "p1 Reference count = " << p1.use_count() << std::endl;

	// 第2个 shared_ptr 对象指向同一个指针
	std::shared_ptr<int> p2(p1);

	// 下面两个输出都是:2
	std::cout << "p2 Reference count = " << p2.use_count() << std::endl;
	std::cout << "p1 Reference count = " << p1.use_count() << std::endl;

	// 比较智能指针,p1 等于 p2
	if (p1 == p2) {
		std::cout << "p1 and p2 are pointing to same pointer\n";
	}

	std::cout<<"Reset p1 "<<std::endl;

	// 无参数调用reset,无关联指针,引用个数为0
	p1.reset();
	std::cout << "p1 Reference Count = " << p1.use_count() << std::endl;
	
	// 带参数调用reset,引用个数为1
	p1.reset(new int(11));
	std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;

	// 把对象重置为NULL,引用计数为0
	p1 = nullptr;
	std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;
	if (!p1) {
		std::cout << "p1 is NULL" << std::endl; // 输出
	}
	return 0;
}

4. weak_ptr

利用weak_ptr可解决shared_ptr循环引用导致的内存泄露问题,具体参考
https://blog.csdn.net/albertsh/article/details/82286999

总结

shared_ptr可以共享内存,每次共享计数器加1,在离开函数作用域或对象析构时计数器减1,计数器为0时析构,可复制.
weak_ptr是辅助shared_ptr用的,可共享,但不增加计数器,使用前需要判断所指向的对象是否还在
unique_ptr独占内存,不可共享,也就不能复制,但可以交出内存对象所有权。在离开函数作用域或对象析构时可自动析构所指向的对象。

关于三者介绍详见https://zhuanlan.zhihu.com/p/92815756

参考:

  1. https://blog.csdn.net/shaosunrise/article/details/85228823
  2. https://blog.csdn.net/fengbingchun/article/details/52202007
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值