C++11智能指針

  爲了解決C++內存泄漏的問題,C++11引入了智能指針(Smart Pointer)。ios

  智能指針的原理是,接受一個申請好的內存地址,構造一個保存在棧上的智能指針對象,C++中有一個重要原則,在函數結束時(不管是正常返回,仍是由於異常除法的對戰回退),會將全部棧對象銷燬,也就是會調用全部棧對象的析構函數。智能指針內部保存的內存也就被釋放掉了(除非將智能指針保存起來)。數組

  C++11提供了三種智能指針:std::shared_ptr, std::unique_ptr, std::weak_ptr,使用時需添加頭文件<memory>。安全

  shared_ptr使用引用計數,每個shared_ptr的拷貝都指向相同的內存。每使用他一次,內部的引用計數加1,每析構一次,內部的引用計數減1,減爲0時,刪除所指向的堆內存。shared_ptr內部的引用計數是安全的,可是對象的讀取須要加鎖。函數

1. shared_ptr

1.1 基本用法

(1)初始化this

  能夠經過構造函數、std::make_shared<T>輔助函數和reset方法來初始化shared_ptrspa

#include "stdio.h"
#include<memory>
#include<iostream>
using namespace std;

void main()
{
    shared_ptr<int> p1(new int(10));
    cout << "p1的引用計數:"<<p1.use_count() << endl;
    shared_ptr<int> p2 = p1; 
    cout << "p1的引用計數:" << p1.use_count() << " p2的引用計數:" << p2.use_count() << endl;
    p2.reset(new int(2));   // 當智能指針中有值時,調用rest會使引用計數減1
    cout << "p1的引用計數:" << p1.use_count() << " p2的引用計數:" << p2.use_count() << endl;
    cout << *p2 << endl;
    p2.reset(); 
    cout << "p1的引用計數:" << p1.use_count() << " p2的引用計數:" << p2.use_count() << endl;

    shared_ptr<int> p3 = make_shared<int>(20); 
    shared_ptr<int> p4;
    p4.reset(new int(30));
    cout << "p4的引用計數:" << p4.use_count() << endl;
}

注意:不能將一個原始指針直接賦值給一個智能指針指針

std::shared_ptr<int> p4 = new int(1);// error

  reset()包含兩個操做。當智能指針中有值的時候,調用reset()會使引用計數減1.當調用reset(new xxx())從新賦值時,智能指針首先是生成新對象,而後將就對象的引用計數減1(固然,若是發現引用計數爲0時,則析構舊對象),而後將新對象的指針交給智能指針保管。rest

(2)獲取原始指針code

std::shared_ptr<int> p4(new int(5));
int *pInt = p4.get();

(3)指定刪除器對象

  智能指針能夠指定刪除器,當智能指針的引用計數爲0時,自動調用指定的刪除器來釋放內存。std::shared_ptr能夠指定刪除器的一個緣由是其默認刪除器不支持數組對象,這一點須要注意。

template<class T, class D>
shared_ptr(T *p, D d)
void DeleteIntPtr(int *p)
{
     delete p;      
}

shared_ptr<int> p(new int(1), DeleteIntPtr);

  當咱們使用shared_ptr管理動態數組時,須要指定刪除器,由於std::shared_ptr的默認刪除器不支持數組對象

shared_ptr<int> p(new int[10], [](int *p){delete[] p;});

  也可使用syd::default_delete做爲刪除器,default_delete的內部是經過調用delete來實現的

shared_ptr<int> p(new int[10], deault_delete<int[]>);

(4)注意make_share和make_arrar_share的使用

(5)使用shared_ptr注意事項

a. 不要用一個原始指針初始化初始化多個shared_ptr

b. 不要在函數實參中建立shared_ptr

2. unique_ptr獨佔指針

  unique_ptr是一個獨佔型的智能指針,它不容許其它的智能指針共享其內部的指針,不容許經過賦值將一個unique_ptr賦值給另一個unique_ptr,unique_ptr不容許複製,但能夠經過函數返回給其它的unique_ptr,還能夠經過move來轉移到其它的unique_ptr,這樣它自己就再擁有原來指針的全部權。

注意:unique_ptr不支持make_share

3. weak_ptr弱引用指針

  弱引用指針week_ptr是用來監視shared_ptr的,不會使引用計數加1,它無論理shared_ptr內部的指針,week_ptr沒有重載操做符,不共享指針,不操做資源。weak_ptr指針能夠用來返回this指針和解決循環引用的問題

(1)use_count獲取當前觀測資源的引用計數

shared_ptr<int> p(new int(1));
weak_ptr<int> p1(p);
cout << p1.use_count() <<endl;

(2)經過expired()來判斷觀測的資源是否已經被釋放

(3)經過lock()來獲取監視的shared_ptr

(4)weak_ptr返回this指針

  不能直接將this指針返回爲shared_ptr,須要經過派生std::enable_shared_from_this類,並經過其方法shared_from_this來返回智能指針,緣由是enable_shared_from_this類中有一個weak_ptr指針,這個weak_ptr用來觀測this智能指針,調用shared_from_this,會調用內部的weak_ptr的lock()方法

(5 )weak_ptr解決循環引用的問題

 

#include "stdio.h"
#include<memory>
#include<iostream>
using namespace std;

class B;
class A
{
public:
    shared_ptr<B> bptr;
    ~A()
    {
        cout << "A is delete!" << endl;
    }
};

class B
{
public:
    shared_ptr<A> aptr;
    ~B()
    {
        cout << "B is delete!" << endl;
    }
};
void main()
{
    {
        shared_ptr<A> a(new A());
        shared_ptr<B> b(new B());

        a->bptr = b;
        b->aptr = a;

        cout << "A的引用計數:" << a.use_count() << endl;
        cout << "B的引用計數:" << b.use_count() << endl;
    }

    int i = 0;
}

離開做用域後引用計數減1,不會去刪除指針,致使內存泄漏

經過weak_ptr解決該問題,只要將A或B中的任意一個成員改爲weak_ptr便可

相關文章
相關標籤/搜索