智能指针

1 变量保存

  1. 静态内存区:保存局部static对象、类static数据成员以及任何函数之外的变量。
  2. 栈内存:保存定义在函数内的非static对象。分配在静态或栈内存中
  3. 堆内存:保存动态分配的对象。
  4. 分配在静态或栈中的对象由编译器自动创建和销毁。
  5. 生命周期:对于栈对象,仅在其定义的程序块运行时才存在;static对下那个在使用之前分配,在程序结束时销毁。动态对象的生存有程序控制,在不使用时,程序必须显式地销毁它们。

2 智能指针

智能指针是模板,比必须给出类型。其使用方式和普通指针类似。解引用一个只能指针返回它指向的对象。如果在一个判断语句中使用只能指针,效果是检测它是否为空。

2.1 shared_ptr

(1)shared_ptr的定义和使用:

一种最安全的分配和使用动态内存的方法:使用make_share 标准库函数
make_shared 定义在memory中

#include <memory>
using namespace std;
int main()
{
	//默认初始化的智能指针中保存着一个空指针
	std::shared_ptr<std::string> p1;	//shared_ptr,可以指向string
	std::shared_ptr<list<int>> p2;

	//如果p1不为空,检查它是否指向一个空string
	if (p1 && p1->empty())
		*p1 = "hi";	//解引用,并赋值
	//指向一个值为42的int的shared_ptr
	shared_ptr<int> p3 = make_shared<int>(42);
	//指向一个值为"9999999999"的string,可以使用string的构造函数
	shared_ptr<string> p4 = make_shared<string>(10, '9');
	//不提供任何参数,执行值初始化
	shared_ptr<int> p5 = make_shared<int>();
	//指向一个动态分配的空的vector<int>
	auto p6 = make_shared<vector<int>>();
	
	return 0;
}

以上几种是使用make_shared函数的例子。

(2)shared_ptr的拷贝和赋值

auto p = make_sahred<int>(42);	//p指向的对象只有p一个引用
auto q(p);	//p和q都指向相同对象,此对象有两个引用者

auto r = make_shared<int>(42);	///r指向的int只有一个引用者
r = q;	//给r赋值,令它指向另一个地址
		//递增q指向的对象的引用计数	
		//递减r原来指向的对象的引用计数
		//r原来的对象已没用引用者,会自动释放

每一个shared_ptr都有一个关联的计数器,称为引用计数。拷贝一个shared_ptr:用一个shared_ptr初始化另一个shared_ptr,或将其作为参数传递给一个函数,或作为一个函数的返回值,它的引用计数都会递增。
当给shared_ptr赋予一个新值或是shared_ptr被销毁时,引用计数就会递减。

当一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象。
即 当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr类会自动销毁此对象,同时也会自动动态对象的内存。

(3)shared_ptr和new结合使用

如果我们不初始化的智能指针,它就会被初始化为一个空指针。除了make_shared,还可以使用new返回的指针初始化只能指针

shared_ptr<double> p1;
shared_ptr<int>p2(new int(42));

接收指针参数的智能指针构造函数是explicit的,因此不能将一个内置指针隐转换为一个智能指针,必须使用直接初始化的方式。
同样的,一个返回shared_ptr的函数不能在其返回语句中隐式转换一个普通指针

shared_ptr<int> p1 = new int(1024);	//错误,必须使用直接初始化的方式
shared_ptr<int>p2(new int(1024));	//正确。

shared_ptr<int> foo(int p)
{
	return new int(p);	//错误,隐式转换为shared_ptr
}
shared_ptr<int> foo(int p)
{
	return shared_ptr<int>(new int(p));	//正确
}

一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象。

(4)不要混合使用普通指针和智能指针

//在函数被调用是ptr被创建被初始化
vodi process(shared_ptr<int> ptr)
{

}	//ptr离开作用域,被销毁

shared_ptr<int> p(new int(42));	//引用计数为1
process(p);	//拷贝p会递增引用计数,在process中为2
int i = *p;	//正确,引用计数为1

int *x(new int(1024));	//x是一个普通指针
process(x);	//错误,不能将int *转换为shared_ptr<int>
process(shared_ptr<int>(x));	//合法,但内存会释放
int j = *x;	//未定义的:x 是一个空悬指针

process函数是值传递的,因此调用process时,会拷贝一份实参,在process中的ptr的引用计数会递增,当离开process后,ptr会被销毁,引用计数递减。
对于指针x,调用process时,创建了一个临时的shared_ptr传递个process,这个临时shared_ptr指向的内存与x指向的内存是用一块内存,当离开process作用域后,临时对象就被销毁了,它所指向的内存也会被释放。当x继续指向(已经释放的)内存,从而变成一个空悬指针。

(5) 不要使用get 初始化一个只能指针或为一个指针赋值

智能指针的get函数返回一个内置指针,它指向智能指针管理的对象。

shared_ptr<int> p(new int(42));	//引用计数wei 1
int *q = p.get();	//正确,但是不要让它管理的指针被释放
{
//未定义,两个独立的shared_ptr<int>指向相同的内存
shared_ptr<int>(q);
}//程序块结束,q被销毁,它所指向的内存被释放
int foo = *p;	//未定义,p指向的内存已经被释放
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值