c++动态内存与智能指针

在c++中,动态内存的管理是用过一对运算符来完成的,new在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以对这个对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并且释放与该对象关联的内存

动态内存的使用非常容易出现问题,因为确保在正确的时间释放内存是及其困难的事情,有时我们会忘记释放内存,这种情况下就会导致内存泄漏,还有的时候,在还有某个指针引用内存的情况下,我们就释放了他,这种情况下,就会出现非法指针

因此,为了应对上述情况,更加安全的使用动态内存,新的标准库提供了以下智能指针,包含在(memory中)
auto_ptr (c++11中已经删除)
unique_ptr :独占指针;
shared_ptr : 共享指针;
weak_ptr :一种弱引用指针;

shared_ptr类

类似于vector,智能指针也是模板,因此在创建的时候,需要指定一下指针所指向的类型,如下

shared_ptr<int> p1;
unique_ptr<int> p2;

默认初始化的智能指针中保存着一个空指针

智能指针的使用方式

智能指针的使用方式和普通指针类似,解引用返回的是它所指向的对象

make_shared函数
最安全的分配和使用动态内存的方法就是调用这个函数,这个函数在动态内存中分配一个对象并且初始化它,返回的是指向这个对象的shared_ptr(定义在memory中)

shared_ptr<int> p3 = make_shared<int>(45);

调用的时候传递的参数必须与类型的某个构造函数匹配,当然也可以用auto来保存其结果

shared_ptr 的拷贝和赋值

当进行拷贝与复制的时候,每个shared_ptr都会记录有多少个其他shared_ptr指向同一个对象,也就是有一个计数器,通常称为引用计数,不管什么时候拷贝一个shared_ptr,计数器都会递增,当shared_ptr被赋予一个新值或者被销毁的时候,计数器会递减,当shared_ptr的计数器为0的时候,他会自动的释放自己所管理的对象

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

当指向一个对象的最后一个shared_ptr被销毁的时候,shared_ptr类会自动销毁此对象,他是通过成员函数–析构函数完成的,shared_ptr的析构函数会递减它所指向的对象的引用计数,如果引用计数为0,他会销毁对象,并且释放所占用的内存

shared_ptr自动释放相关联的内存
shared_ptr<Foo> factory(T arg)
{
	return make_shared<Foo>(arg);
}
void use_factory(T arg)
{
	shared_ptr<Foo> p = factory(arg);//p是局部变量,当出了其作用域之后,他所指向的内存被自动释放掉
}

shared_ptr usefactory(T arg)
{
	shared_ptr<Foo> p = factory(arg);
	return p;//由于返回的是p的拷贝,计数器+1,当出了其作用域之后,计数器-1,但是他所指向的内存还有使用者,所以并不会被释放掉
}
程序使用动态内存的原因
  1. 程序不知道自己需要使用多少对象
  2. 程序不知道所需对象的准确模型
  3. 程序需要在多个对象间共享数据
shared_ptr 成员函数
  1. use_count 返回引用技术的个数
  2. unique返回是否独占所有权(use_count = 1)
  3. swap 交换两个shared_ptr对象
  4. reset放弃内部对象的所有权,会引起原有对象的引用计数的减少
  5. get 返回内部对象
unique (替换auto-ptr)

unique_ptr实现的是独占式的占有,保证同一时间只有一个智能指针可以指向该对象,他对于造成资源泄露有非常重要的作用。

unique_ptr<string> p3(new string("new"));
unique_ptr<string> p4;
p4 = p3;

最后一句会导致出错,编译器认为p4=p3 非法,= 使用赋值函数,将p3拷贝赋值给p4,使两者指向的是同一段内存,违反了独占式的占有

另外unique_ptr有一个比较聪明的地方

unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1;//1                                         
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string ("You")); //2         

如上代码,1 是不允许的,2 是允许的,unique_ptr(new string (“You”));产生了一个临时对象,将这个临时对象拷贝给pu3之后,临时对象被销毁。

当然如果想要使用1的做法,也是可以的,可以同构移动语义来使unique_ptr赋值给另一个,如下

unique_ptr<string> ps1, ps2;
ps1 = demo("hello");
ps2 = move(ps1);
ps1 = demo("alexia");
cout << *ps2 << *ps1 << endl;
weak_ptr

weak_ptr 是一中不控制对象声明周期的智能指针,他指向的是一个shared_ptr管理的对象,进行该对象的内存管理的还是shared_ptr,weak_ptr知识提供了对管理对象的一个访问手段,weak_ptr设计的初衷是为了解决shared_ptr的循环引用问题,如果说两个shared_ptr相互引用的话,会导致计数器永远无法归0 ,这个时候就可以将其中一方修改成weak_ptr,他并不会使shared_ptr的计数器加一,并且还可以和shared_ptr相互转化,shared_ptr可以直接赋值给他,而它可以通过lock函数来获得shared_ptr

class A
{
public:
shared_ptr<B> pb_;
~A()
{
cout<<"A delete\n";
}
};
class B
{
public:
shared_ptr<A> pa_;
~B()
{
cout<<"B delete\n";
}
};

注意的是我们不能通过weak_ptr直接访问对象的方法,比如B对象中有一个方法print(),我们不能这样访问,pa->pb_->print(); 英文pb_是一个weak_ptr,应该先把它转化为shared_ptr,如:shared_ptr p = pa->pb_.lock(); p->print();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值