c++11智能指针使用

智能指针是c++很重要的一项技术,面试经常会问,诸如以下几个问题:

  • shared_ptr的原理是什么?
  • shared_ptr是线程安全的吗?
  • 如何把指针赋给已存在的shared_ptr?
  • 什么情况下使用unique_ptr?
  • 如何将unique_ptr对象的所有权转移给另外一个unique_ptr?
  • weak_ptr解决了什么样的问题?

智能指针管理的是动态内存的指针,是new出来的,那么什么情况下需要使用动态内存呢?

有以下几点:

  1. 程序不知道自己需要使用多少个对象
  2. 程序不知道所需对象的准确类型
  3. 程序需要在多个对象间共享数据

c++管理动态内存主要通过new和delete,实际开发中存在两种严重的问题:

  1. 忘记释放内存造内存泄漏
  2. 尚有指针引用内存的情况下就释放了它,造成非法引用。

使用智能指针能够有效解决以上问题。

  • shared_ptr
  • unique_ptr
  • weak_ptr

三者的头文件是<memory>

一、shared_ptr
1.如何初始化?

shared_ptr<string> p;//空智能指针。
类似vector,智能指针也是模板,以上代码实际上是以默认初始化的方式,它保存着一个空指针。直接使用会出现段错误。

两种初始化方式:

<1>shared_ptr<string> sp1(new string("123"));//构造函数直接初始化

<2> shared_ptr<string> sp2 = make_shared<string>("123");

<3>shared_ptr<string>sp3(sp2);//这实际上时调用了拷贝构造,两个shared_ptr引用到同一个对象。

Note:

make_shared函数在动态内存中分配一个对象并初始化它,返回指向该对象的shared_ptr,它更加安全和稳定,自己new对象可能会抛异常。

在调用make_shared的时候传递的参数必须与该类的构造函数相匹配。


2.如何把一个已存在的动态内存指针赋给shared_ptr管理?
使用reset函数,代码如下:

shared_ptr<string> sp;
sp = new string("123");//错误,不能把一个指针赋值给shared_ptr
正确的做法是:
sp.reset(new string("123"));//这个在实际开发中,尤其重要。


3.智能指针较普通指针的优势?

实际开发中,难免会遇到异常,忘记delete,造成内存泄漏。

void fun(){
     shared_ptr<int> sp(new int(10));
    //在此处抛出异常,fun没有被捕获
}//函数结束时,shared_ptr依然能释放内存

void fun(){
     int *p = new int(10);
    //在此处抛出异常,fun没有被捕获
    delete p;
}//函数结束时候,p指向的内存永远得不到释放了。


4.如何自定义删除器?
如果使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器。

void myfree(void *p){
      delete p;
}
int *x = new int(1);

shared_ptr<int> p(x,myfree); //自定义删除器

5.shared_ptr是线程安全的吗?

shared_ptr的引用计数本身是线程安全的,因为在发生拷贝、赋值、删除的时候,对引用计数明确。

shared_ptr本身不是引用计数类,它只是包含了一个指向引用计数类sp_counted_base的指针,sp_counted_base类才保存了引用计数,并且对引用计数字段提供无锁保。

6.shared_ptr相互引用的危害?

看一下以下代码:

class A{
public:
    shared_ptr<B> pB;
};

class B{
public:
    shared_ptr<A> pA;
};

int main(int argc,char *argv[]){

    shared_ptr<A> spa(new A);
    shared_ptr<B> spb(new B);
    spa->pB = spa;
    spb->pA = spb;
}

以上代码会出现相互引用,智能指针的引用计数永远到不了0,造成内存泄漏。

解决办法:创建对象的时候,shared_ptr持有它,当其他地方想使用这个对象的时候,应该持有该对象的弱智能指针(weak_ptr)。

7.使用shared_ptr有哪些注意点?

  • 不使用相同的内置指针初始化或reset多个智能指针
  • 不delete get()返回的指针
  • 不使用get()初始化或者reset另外一个指针
  • 如果使用智能指针管理的资源不是new分配的内存,记住传递它一个删除器
  • 使用weak_ptr解决相互引用的问题。


二、unique_ptr
某一时刻只能有一个unique_ptr指向一个给定对象,也就是独占式的。

没有像make_shared类似的函数初始化,不支持拷贝和赋值。

虽然不能拷贝和赋值,但是可以通过release和reset来从一个非const unique_ptr转移给另外一个unique

使用示例

unique_ptr<string> p1(new string("text"));

unique_ptr<string>p2(p1.release());//从p1转移给p2,release将p1置于空

unique_ptr<string>p3(new string(text1));

p2.reset(p3.release());//reset释放了p2原来指向的内存

p2.release();//p2不会释放内存,而且丢失了指针

auto p = p2.release();//合法,但是要delete p

Note:

不能拷贝的规则有一个例外,那就是可以拷贝或赋值一个将被销毁的unique,比如从函数返回值。

未完...

 

 

 

 

 


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值