C++ 智能指針

C++11智能指針介紹

智能指針主要用於管理在堆上分配的內存,它將普通的指針封裝爲一個棧對象。當棧對象的生存週期結束後,會在析構函數中釋放掉申請的內存,從而防止內存泄漏。ios

爲何要使用智能指針

智能指針的做用是管理一個指針,由於存在如下這種狀況:申請的空間在函數結束時忘記釋放,形成內存泄漏。使用智能指針能夠很大程度上的避免這個問題,由於智能指針就是一個類,當超出了類的做用域是,類會自動調用析構函數,析構函數會自動釋放資源。因此智能指針的做用原理就是在函數結束時自動釋放內存空間,不須要手動釋放內存空間,有效避免內存泄漏的問題c++

智能指針定義於 memory (非memory.h)中, 命名空間爲 std函數

unique_ptr

unique_ptr,是用於取代c++98的auto_ptr的產物指針

unique_ptr 獨佔所指向的對象, 同一時刻只能有一個 unique_ptr 指向給定對象(經過禁止拷貝語義, 只有移動語義來實現), 定義於 memory (非memory.h)中, 命名空間爲 std.調試

  • 1.unique_ptr 是禁止複製賦值的,始終保持一個 unique_ptr 管理一個對象。
  • 2.unique_ptr 雖然不能賦值,但能夠經過 move() 函數轉移對象的全部權。一旦被 move() 了,原來的 up1 則再也不有效了。
  • 3.reset() 可讓 unique_ptr 提早釋放指針。

auto_ptr

(C++98的方案,C++11已經拋棄)採用全部權模式。
auto_ptr 適合用來管理生命週期比較短或者不會被遠距離傳遞的動態對象, 最好是侷限於某個函數內部或者是某個類的內部.code

因爲 auto_ptr 基於排他全部權模式:兩個指針不能指向同一個資源,複製或賦值都會改變資源的全部權。對象

#include <iostream>
#include <memory>

class Test
{
public:
    void print()
    {
        std::cout << "Test::Print" << std::endl;
    }
};

int main()
{
    std::auto_ptr<Test> pTest1(new Test);
    pTest1->print();

    std::auto_ptr<Test> pTest2(pTest1);     //複製構造函數
    pTest2->print();

    std::cout << "pTest1 pointer:" << pTest1.get() << std::endl;    //auto_ptr類的成員函數get()返回一個原始的指針
    std::cout << "pTest2 pointer:" << pTest2.get() << std::endl;

    return 0;
}

//打印結果:
Test::Print
Test::Print
pTest1 pointer:00000000
pTest2 pointer:01659548

//通過複製構造以後,pTest1所指向資源的全部權轉向了pTest2,而pTest1變成空,兩者不能同時共享該資源。

auto_ptr 主要有兩大問題:生命週期

  • 複製和賦值會改變資源的全部權,不符合人的直覺。
  • 在 STL 容器中沒法使用auto_ptr ,由於容器內的元素必需支持可複製(copy constructable)和可賦值(assignable)。

shared_ptr(C++11中新增的智能指針)

基於引用計數模型。資源能夠被多個指針共享,它使用計數機制來代表資源被幾個指針共享。內存

每次有 shared_ptr 對象指向資源,引用計數器就加1;當有 shared_ptr 對象析構時,計數器減1;當計數器值爲0時,被指向的資源將會被釋放掉。且該類型的指針可複製和可賦值,即其可用於STL容器中。此外,shared_ptr 指針可與多態類型和不徹底類型一塊兒使用。資源

std::shared_ptr 智能指針共享所指向的資源(全部權),即幾個 shared_ptr 可同時擁有一個對象,且共享一個控制塊(constrol block),包含指向資源的 shared_ptr對象個數、指向資源的 weak_ptr 對象個數以及刪除器(deleter:用戶自定義的用於釋放資源的函數,能夠默認沒有)。

一個空的 shared_ptr 對象不擁有任何資源和控制塊。另外一方面,一個 shared_ptr 初始化爲一個NULL 指針和一個控制塊,這有別有空的 shared_ptr。當共享的引用計數器爲0時,資源釋放(delete 操做符釋放,或由用戶提供的 刪除器 釋放它)。

#include <iostream>
#include <memory>

class Test
{
public:
    void print()
    {
        std::cout << "Test::Print" << std::endl;
    }
};

int main()
{
    std::shared_ptr<Test> pTest1(new Test);
    pTest1->print();

    std::shared_ptr<Test> pTest2(pTest1);    //複製構造函數
    pTest2->print();

    std::cout << "pTest1 pointer:" << pTest1.get() << std::endl;    //shared_ptr類的成員函數get()返回一個原始的指針
    std::cout << "pTest2 pointer:" << pTest2.get() << std::endl;

    std::cout << "count pTest1:" << pTest1.use_count() << std::endl; //shared_ptr類的成員函數use_count():返回多少個智能指針指向某個對象,主要用於調試。
    std::cout << "count pTest2:" << pTest2.use_count() << std::endl;


    return 0;
}

//打印結果:
Test::Print
Test::Print
pTest1 pointer:00C29550
pTest2 pointer:00C29550
count pTest1:2
count pTest2:2

//pTest2建立後,pTest1對資源的全部權並無被剝奪,而是pTest1 和 pTest2 均指向了資源,且此時資源的引用計數爲2。當兩個shard\_ptr 指針pTest一、pTest2 超過其做用域時,最後一個析構的指針將會導致資源的釋放(由於引用計數爲0了)。

shared_ptr的使用

待補充。。。

主要缺點:

shared_ptr相互引用,那麼這兩個指針的引用計數永遠不可能降低爲0,資源永遠不會釋放。

沒法檢測出循環引用,這會形成資源沒法釋放,從而致使內存泄露。

爲了 fix 這個問題,C++11引入了另外一個智能指針:weak_ptr

weak_ptr(C++11中新增的智能指針)

weak_ptr工做原理

weak_ptr是用來解決shared_ptr相互引用時的死鎖問題,若是說兩個shared_ptr相互引用,那麼這兩個指針的引用計數永遠不可能降低爲0,資源永遠不會釋放。它是對對象的一種弱引用,不會增長對象的引用計數,和shared_ptr之間能夠相互轉化,shared_ptr能夠直接賦值給它,它能夠經過調用lock函數來得到shared_ptr。

做用在於協助 shared_ptr 工做,可得到資源的觀測權,像旁觀者那樣觀測資源的使用狀況。觀察者意味着 weak_ptr 只對 shared_ptr 進行引用,而不改變其引用計數,當被觀察的 shared_ptr 失效後,相應的 weak_ptr 也相應失效。

weak_ptr更像是shared_ptr的助手:

  • 一、他不像其他三種,能夠經過構造函數直接分配對象內存;他必須經過shared_ptr來共享內存。
  • 二、沒有重載opreator*和->操做符,也就意味着即便分配到對象,他也無法使用該對象
  • 三、不主動參與引用計數,即share_ptr釋放了,那麼weak_ptr所存的對象也釋放了。
  • 四、使用成員函數use_count()能夠查看當前引用計數,expired()判斷引用計數是否爲空。
  • 五、lock()函數,返回一個shared_ptr智能指針:也就是讓weak_ptr觀測shared_ptr智能指針,而且在須要時候經過lock函數返回一個shared_ptr。

weak_ptr使用

待補充。。。

相關文章
相關標籤/搜索