智能指針的原理和實現


1.智能指針的作用

C++程序設計中需要頻繁地動態分配堆內存,堆內存的申請和釋放都由程序員管理。程序員管理堆內存提高了程序的效率,但是整體來說堆內存的管理非常麻煩,且容易造成動態分配的堆內存沒有正確釋放或無法釋放,導致資源浪費,程序運行速度變慢等問題。為了解決這些問題C++11提出了智能指針的概念,方便管理內存。

使用普通指針容易造成內存泄漏、二次釋放、程序發生異常時內存泄漏等問題,使用智能指針可以更好地管理堆內存。

理解智能指針從以下三個方面入手:

1.智能指針是利用了一種叫做RAII(資源分配即初始化)的概念堆普通指針進行封裝,這使得智能指針實質上是一個類對象,但表現得卻像一個指針。

2.智能指針的作用是防止調用delete釋放內存或者程序異常進入catch塊忘記釋放內存,同時多次釋放同一指針會導致程序崩潰。

3.智能指針可以把值語義轉換成引用語義,C++和Java有一處最大的區別在於語義不同,在Java里面下列代碼:

  Animal a = new Animal();

  Animal b = a;

     你當然知道,這里其實只生成了一個對象,a和b僅僅是把持對象的引用而已。但在C++中不是這樣,

     Animal a;

     Animal b = a;

     這里卻是就是生成了兩個對象。

二:智能指針的使用

智能指針在C++11后提供,包含在頭文件<memory>中,shared_ptr,unique_ptr,weak_ptr

2.1shared_ptr的使用:

shared_ptr多個指針指向相同的對象,shared_ptr使用引用計數,每一個shared_ptr的拷貝都指向相同的內存,每使用它一次,內部的引用計數加一,每析構一次,內部的引用計數減1,減為0時,自動釋放所指向的堆內存。shared_ptr內部的引用計數是線程安全的,但是對象的讀取需要加鎖。

  • 初始化:智能指針是一個模板類,可以指定類型,傳入指針通過構造函數初始化。也可以使用make_shared函數初始化。不能將指針直接復制給一個智能指針,因為一個是類,一個是指針
  • 拷貝和賦值。拷貝使得對象的引用計數加1,賦值使得原對象的引用計數減一,當引用計數為0時,自動釋放內存。后來指向的對象的引用計數加1,指向后來的對象
  • get函數獲取原始指針
  • 不要用一個原始指針初始化多個shared_ptr,會造成二次釋放同一內存。
    #include <iostream>
    #include<memory>
    using namespace std;
    
    
    int main()
    {
    	int a = 1;
    	shared_ptr<int>ptr1 = make_shared<int>(a);
    	shared_ptr<int>ptr2(ptr1);//copy
    
    	cout << ptr1.use_count() << endl;
    	cout << ptr2.use_count() << endl;
    
    	int b = 20;
    	int* pb = &a;
    	//shared_ptr<int>ptrb = pb;//error不允許直接將指針賦值給類
    	shared_ptr<int>ptrb = make_shared<int>(b);
    	ptr2 = ptrb;//賦值
    	cout << ptr1.use_count() << endl;
    	cout << ptrb.use_count() << endl;
    pb = ptrb.get();//獲取原始指針    system("pause"); return 0; }

    2.2 unique_ptr的使用

unique_ptr唯一擁有其所指對象,同一時刻只有一個unique_ptr指向給定對象(禁止賦值和拷貝,直接賦值會編譯出錯,只有通過移動語義來實現)。unique_ptr指針的生命周期:從unique_ptr創建開始,直到離開作用域。離開作用域時,若其指向對象,則將其所指向對象銷毀(默認使用delete操作符)。unique_ptr指針其所指對象的關系:在智能指針生命周期內,可以改變智能指針所指對象,如創建智能指針時通過構造函數指定、通過reset方法重新指定、通過release方法釋放所有權、通過移動語義轉移所有權。

int main()
{
    unique_ptr<int>uptr(new int(10));//傳入指針,調用構造函數
    //unique_ptr<int>uptr2 = uptr;//不能賦值
    //unique_ptr<int>uptr3 (uptr);//不能拷貝
    unique_ptr<int>uptr3 = move(uptr);//轉移所有權,移動語義
}

2.3 weak_ptr的使用

weak_ptr是為了配合shared_ptr而引入的一種智能指針,因為它不具備普通指針的行為,沒有重載operator*和->,它最大作用在於協助shared_ptr工作,像旁觀者那樣觀測資源的使用情況。weak_ptr可以從一個shared_ptr或者另一個weak_ptr構造,獲得資源的觀測勸,不增加引用計數,沒有共享資源。使用weak_ptr的成員函數use_count()可以觀測資源的引用計數,另一個成員函數expired()的功能等價於use_count=0,但更快,表示被觀測的資源(shared_ptr管理的資源)已經不存在了。weak_ptr可以用lock()從被觀測的shared_ptr獲得一個可用的shared_ptr對象,從而操作資源。當expired()==true時,lock函數將返回一個存儲空指針的shared_ptr。

int main() {
    {
        std::shared_ptr<int> sh_ptr = std::make_shared<int>(10);
        std::cout << sh_ptr.use_count() << std::endl;

        std::weak_ptr<int> wp(sh_ptr);
        std::cout << wp.use_count() << std::endl;

        if (!wp.expired()) {
            std::shared_ptr<int> sh_ptr2 = wp.lock(); //get another shared_ptr,增加了引用計數
            *sh_ptr = 100;
            std::cout << wp.use_count() << std::endl;
            std::cout << sh_ptr.use_count() << std::endl;
        }
    }
    //delete memory
        system("pause");
        return 0;
}

三:智能指針的實現

https://www.cnblogs.com/wxquare/p/4759020.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM