智能指针问题总结

 智能指针

(1)定义:

       智能指针是行为类似于指针的类对象,但其功能多于指针。

说明:c++程序设计中经常会用堆内存,程序员要自己管理内存的申请和释放。使用原始指针,容易造成堆内存泄漏(忘记释放),二次释放;使用智能指针能更好的管理堆内存。智能指针本质是存放在栈的模板对象,只是在栈内部包了一层指针,其类内部有析构函数。而栈在其生命周期结束时,其中的指针指向的堆内存也自然被析构函数释放了。因而实现了智能管理的效果,不需要考虑内存问题了,其实有点类似某种单例写法,程序运行结束,也不用考虑单例对象内存问题。

本次讨论:c++11之前的auto_ptr; c++11新加的unique_ptr, shared_ptr

(2)构造

模板类的构造:
   

 template<class X> class auto_ptr

{

public:

    explicit auto_ptr(X* p=0) throw();

}

模板类的实例化

   头文件:#include <memory>

   auto_ptr<double> pd(new double);

  auto_ptr<string> ps(new string);

  auto_ptr<report> pr(new report(“this is a class”));

  //report是一个类,可通过pr调用类的方法。

        其中new double 是new返回的指针,指向新分配的内存块,new double也是构造函数的实参。

  unique_ptr<double> pdu(new double);

  shared_ptr<double>pds(new double);

(3)指针和智能指针的隐式转换问题:

        所有智能指针都不允许进行隐式转换。

例:shared_ptr<double> pds;

        double *p_reg = new double;

        pds = shared_ptr<double>(p_reg);

       //pds = p_reg;非法

       shared_ptr<double> pshared (p_reg);//复制构造函数

      // shared_ptr<double> pshared = p_reg;非法

(4)三种智能指针的区别

例:

#include <iostream>

#include <string>

#include <memory>

using namespace std;

int main()

{

    auto_ptr<string> films[4]=

    {

       auto_ptr<string> (new string("first")),

       auto_ptr<string> (new string("second")),

       auto_ptr<string> (new string("third")),

       auto_ptr<string> (new string("fourth"))

    };

    auto_ptr<string> pwin;

    pwin = films[2];

    for(int i = 0;i<4;i++)

    {

        cout<<*films[i]<<endl;

    }

    cout<<*pwin<<endl;

    return 0;

}

说明:在运行*films输出时出错。原因:pwin = films[2]这句话是auto_ptr放弃了films[2]的所有权,则此时的films[2]是一个空指针,调用时会出错。
 

shared_ptr<string> films[4]=

    {

       shared_ptr<string> (new string("first")),

       shared_ptr<string> (new string("second")),

       shared_ptr<string> (new string("third")),

       shared_ptr<string> (new string("fourth"))

    };

    shared_ptr<string> pwin;

    pwin = films[2];

    for(int i = 0;i<4;i++)

    {

        cout<<*films[i]<<endl;

    }

    cout<<*pwin<<endl;

说明:I、将auto_ptr换成shared_ptr,则输出成功。原因:pwin=films[2]指向同一个对象,shared_ptr中的引用计数从1增加到2.程序结束后,后声明的pwin首先调用析构函数,此时的引用计数减1。然后释放films[2],调用析构函数,此时引用计数减为0,,并释放以前的分配空间。

         II、当使用unique_ptr时,因为它也是用的是所有权模型,所以也会崩溃。但是unique_ptr比auto_ptr更安全,因为若使用unique_ptr,则在pwin=films[2]阶段就会报错(编译阶段错误比潜在的程序崩溃更安全)。

(5)具体来说unique_ptr和shared_ptr指针的区别是:

unique_ptr(独占的智能指针):独占所指向的对象,某个时刻只能有一个unique_ptr指向一个给定对象。当unique_ptr被销毁时,它所指向的对象也被销毁。不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,但可以通过函数返回给其他的unique_ptr,或者用std::move转移到其他的unique_ptr。

shared_ptr(共享的智能指针):允许多个指针指向同一个对象,内部维护一个计数器,无论何时拷贝一个shared_ptr,计数器都会递增,当指向该对象的最后一个shared_ptr被销毁时,shared_ptr类会自动销毁该对象。其中use_count() 有多少个指针指向当前对象,即引用计数。

基本用法:

初始化 优先使用make_shared

I、通过构造函数、shared_ptr辅助函数、reset方法来初始化

shared_ptr<int> p1(new int(1));

shared_ptr p2 = p1;

shared_ptr<int> p3;

p3.reset(new int(1)); // 与赋值类似,reset会更新引用计数,p3指向一个新对象,p3原来指向的对象计数-1

if (p3)

 {

       cout << "p3 not null" << endl;

}

II、应该优先使用make_shared来构造智能指针,更高效

auto p1 = make_shared<int>(100); 相当于shared_ptr<int> sp1(new int(100));

// 不能将原始指针赋值给智能指针

shared_ptr<int> p = new int(1); // error

获取原始指针

shared_ptr<int> ptr(new int(1));

int* p = ptr.get(); // 返回ptr中保存的指针,要小心使用,若智能指针释放了对象,返回的指针所指向的对象也就消失了。

(6)unique_ptr指针中的悬挂指针问题

unique_ptr<string> pu1(new string("unique"));

unique_ptr<string> pu2;

pu2 = pu1;

说明:这种赋值是不合法的,在编译阶段就不通过。因为pu1是一个左值(左值是指表达式结束后依然存在的持久对象),当pu1的所有权已经转让给pu2之后,但它还存在,变成了一个悬挂的智能指针,如果后面使用它,则程序会崩溃。

unique_ptr<string> pu3;  

pu3 = unique_ptr<string>(new string("unique"));

说明:这种赋值是合法的。因为unique_ptr<string>(new string("unique"))是一个右值(右值是指表达式结束时就不再存在的临时对象)。该构造函数创建的临时对象在其所有权转让给pu3后就被销毁。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值