一、什么是智能指针

  一般来讲C++中对于指针指向的对象需要使用new主动分配堆空间,在使用结束后还需要主动调用delete释放这个堆空间。为了使得自动、异常安全的对象生存期管理可行,就出现了智能指针这个概念。简单来看智能指针是 RAII(Resource Acquisition Is Initialization,资源获取即初始化) 机制对普通指针进行的一层封装。这样使得智能指针的行为动作像一个指针,本质上却是一个对象,这样可以方便管理一个对象的生命周期。

  智能指针作用总结:

  1. 处理内存泄漏。
  2. 处理空悬指针的问题。
  3. 处理异常造成的内存泄露。

  注:智能指针和原生指针不要混用,使用不当可能会导致程序异常;

二、智能指针有哪些

  智能指针(动态内存管理)头文件 <memroy>

三、独占式智能指针(std::unique_ptr)

 1 class SmartPointer
 2 {
 3 public:
 4     SmartPointer()
 5     {
 6         cout << "SmartPointer::SmartPointer()" << endl;
 7     }
 8     ~SmartPointer()
 9     {
10 
11         cout << "SmartPointer::~SmartPointer()" << endl;
12     }
13 };

 

  •   独占式:
  •   unique_ptr拥有所指向(管理)的资源、对象的所有权,即不能被其他unique_ptr所指;
  •   unique_ptr不能进行赋值或拷贝操作;
    unique_ptr<SmartPointer> ptest1(new SmartPointer("空格"));
//    unique_ptr<SmartPointer> ptest2 = ptest1;     //此时编译报错
  •   但可以使用std::move或者relase()方法将源unique_ptr 指针指向资源所有权转向新unique_ptr;
    unique_ptr<SmartPointer> ptest1(new SmartPointer("空格"));
    cout << "ptest1 location: " << ptest1.get() << endl;
    unique_ptr<SmartPointer> ptest2 = move(ptest1);         //将ptest1指向对象所有权转移给ptest2,ptest1置空为NULL
    cout << "ptest2 location: " << ptest2.get() << endl;
    unique_ptr<SmartPointer> ptest3(ptest2.release());      //将ptest2指向对象所有权转移给ptest3,ptest2置空为NULL
    cout << "ptest3 location: " << ptest2.get() << endl;

结果为:

  

 

  •   unique_ptr本身拥有的几个主要方法
  1. get() 方法:获取其保存的原生指针,尽量不要使用;
  2. release() 方法:释放所管理指针的所有权,返回原生指针。但并不销毁原生指针;
  3. reset() 方法:释放并销毁原生指针。如果参数为一个新指针,将管理这个新指针;
  4. bool() 方法:判断是否拥有指针;
    unique_ptr<SmartPointer> ptest1(new SmartPointer());
    ptest1.reset(new SmartPointer());   //释放销毁原有对象,持有新对象
    ptest1.reset();     //直接释放销毁原对象
    ptest1 = nullptr;   //同上

四、共享式智能指针(std::shared_ptr)

  •   共享式

  共享权,多个shared_ptr同时拥有一个原生指针(内存)的所有权,最后一个拥有者负责原生指针的释放和销毁;

    std::shared_ptr<SmartPointer> pTest1(new SmartPointer());
    std::shared_ptr<SmartPointer> pTest2 = pTest1;              //编译正常,允许所有权的共享
    cout  << "pTest1 location: " << pTest1.get() << endl;
    cout  << "pTest2 location: " << pTest2.get() << endl;
    shared_ptr<SmartPointer> pTest3 = make_shared<SmartPointer>();//新建共享指针方法,make_shared效果类似new
    pTest2 = pTest3;
    cout  << "pTest3 location: " << pTest3.get() << endl;
    cout  << "pTest2 location: " << pTest2.get() << endl;

结果:

  

  •   计数器

  共享指针类中包括一个成员函数用来记住所管理的内存当前有多少个指针指向它;

  use_count()方法可以获取指向对象的shared_ptr个数;

    shared_ptr<string> pStr_1(new string("霜之哀伤"));
    shared_ptr<string> pStr_2 = make_shared<string>("火之高兴");

    auto pStr_3 = pStr_1;   //此时指向“霜之哀伤”数量为2,“火之高兴”为1;
    cout << *pStr_1 << " : " << pStr_1.use_count() << "t"
         << *pStr_2 << " : " << pStr_2.use_count() << endl;
    pStr_3 = pStr_2;        //此时指向“霜之哀伤”数量为1,“火之高兴”为2;
    cout << *pStr_1 << " : " << pStr_1.use_count() << "t"
         << *pStr_2 << " : " << pStr_2.use_count() << endl;

结果:

  

 

 

  •  shared_ptr拥有的几个主要方法:
  1. get() 方法:获取其保存的原生指针,尽量不要使用;
  2. bool() 方法:判断是否拥有指针;
  3. reset() 方法:释放并销毁原生指针。如果参数为一个新指针,将管理这个新指针;
  4. unique() 方法:如果引用计数为 1(即对象所有权唯一),则返回 true,否则返回 false;
  5. use_count() 方法:返回引用计数的大小;
    shared_ptr<SmartPointer> pTest1(new SmartPointer());
    cout << pTest1.unique() << endl;    //此时为true;
    shared_ptr<SmartPointer> pTest2 = pTest1;
    cout << pTest1.unique() << endl;    //此时为false
    pTest1.reset(new SmartPointer());   //释放销毁原有对象,持有新对象
    pTest1.reset();     //直接释放销毁原对象
    pTest1 = nullptr;   //同上

结果:

  

五、辅助指针/弱指针(std::weak_ptr)

class B;

class A
{
public:
    A()
    {
        cout << "A::A()" << endl;
    }
    ~A()
    {
        cout << "A::~A()" << endl;
    }
    shared_ptr<B> pB;
};

class B
{
public:
    B()
    {
        cout << "B::B()" << endl;
    }
    ~B()
    {
        cout << "B::~B()" << endl;
    }
    shared_ptr<A> pA;
};

  weak_ptr是为了辅助shared_ptr所引入的弱引用智能指针,主要是为了解决shared_ptr中循环引用(对象A持有对象B,对象B持有对象A,此时两个对象的引用计数均为2;在跳出作用范围时,两个对象引用计数均减1但还有1,导致跳出作用范围后两个对象的资源没有释放销毁,产生内存泄漏)的问题。

    shared_ptr<A> pA(new A());  //新建A类对象
    shared_ptr<B> pB(new B());  //新建B类对象

    pA->pB = pB;    //A类中持有B类 
    pB->pA = pA;    //B类中持有A类
    //此时构成了循环引用
    cout << pA.use_count() << endl;
    cout << pB.use_count() << endl;

结果:

  循环引用在跳出作用范围时未调用类A与类B析构函数,导致内存泄漏,此时可以将类内的shared_ptr改为weak_ptr可以避免;

  

 

   weak_ptr不能直接使用原生指针构造,可以使用一个shared_ptr和另一个weak_ptr进行构造;

  •   weak_ptr拥有的几个主要方法
  1. expired() 方法:判断所指向的原生指针是否被释放,如果被释放了返回 true,否则返回 false;
  2. use_count() 方法:返回原生指针的引用计数;
  3. lock() 方法:返回 shared_ptr,如果原生指针没有被释放,则返回一个非空的 shared_ptr,否则返回一个空的 shared_ptr;
  4. reset() 方法:将本身置空;
    shared_ptr<A> pA(new A());
    weak_ptr<A> weak_pA = pA;   //弱指针,不增加引用计数
    cout << "A引用计数:" << weak_pA.use_count() << endl;

    shared_ptr<A> pA_1 = weak_pA.lock();    //此时又一个shared_ptr指向原生指针,计数加1
    cout << "A引用计数:" << weak_pA.use_count() << endl;
    
    cout << weak_pA.expired() << endl;
    //销毁原生指针
    pA.reset();
    pA_1.reset();
    cout << weak_pA.expired() << endl;
    weak_pA.reset();    //置空weak_ptr

结果:

  

参考:

https://www.cnblogs.com/corineru/p/10895249.html

https://www.cnblogs.com/TenosDoIt/p/3456704.html

https://zhuanlan.zhihu.com/p/436290273

https://www.csdn.net/tags/MtTaEg0sMTkwMTctYmxvZwO0O0OO0O0O.html

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!