iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0
Software Development

C++ 實務基礎經驗系列 第 19

資源管理 智慧指針

  • 分享至 

  • xImage
  •  

資源管理 智慧指針

智慧指針(smart pointer)是C++11以後出的有關自動釋放資源(記憶體)的函式庫,就是C#, JAVA的GC的功能

資源(記憶體)

我們的程式每次啟動,都會向作業系統(OS)要記憶體來存放跟使用資料,這其中有兩種的記憶體存放方式,

堆 Heap

跟資料結構堆積 Heap名稱很像,但是是不同的東西,這個區塊主要是由使用者分配跟釋放的,如果沒釋放或釋放不乾淨,就有可能導致內存洩漏 Memory Leak,引發程式崩潰,而堆的記憶體位址是從較低位址往高位址

棧 Stack

這個區塊是屬於區域變數的資料,像我們函式裡面的變數就是存放在這區,當離開函式,區域變數的資料都會被系統清掉,不用介入,而棧的記憶體是從較高位址到較低位址的

Smart Pointer

接下來就是介紹C++11出的三種智慧指針類型:shared_ptr, unique_ptr, weak_ptr

shared_ptr

shared_ptr算是最常用的,其中的實作就是對資源引用作記數,引用記數為0的時候,就會自動釋放資源,參考下面例子

#include <iostream>
#include <string>
#include <memory>

using namespace std;

class Cat
{
public:
    Cat() {}
    Cat(string name, int tail):Name(name), TailLen(tail) {}
    ~Cat()
    {
        cout << "Cat " << Name << " free\n";
    }
    string Name = "";
    int TailLen = 0;
};

int main(int argc, char const *argv[])
{
    // 建議用make_shared替代new,因為分配記憶體的位址會有優化,記憶體分配較連續,對性能好
    shared_ptr<Cat> pCat = make_shared<Cat>("cat1", 49);
    cout << "pCat count: " << pCat.use_count() << endl;
    {
        shared_ptr<Cat> pCat2 = pCat;
        cout << "pCat count: " << pCat.use_count() << endl;
        // Cat2跟Cat是同一個物件,離開時引數為1,還不會自動釋放
    }
    cout << "pCat count: " << pCat.use_count() << endl;
    {
        shared_ptr<Cat> pCat3 = make_shared<Cat>("cat3", 55);
        // 會比cat1先釋放,離開作用域,引數就為0
    }

    return 0;
}

unique_ptr

unique_ptrshared_ptr不一樣的是,unique_ptr的指標是唯一的,也就是不能被複製,而因為只能是唯一,性能方面也會比shared_ptr好,參考下面例子

int main(int argc, char const *argv[])
{
    // make_unique是C++14才有的語法
    unique_ptr<Cat> pCat4 = make_unique<Cat>("cat4", 16);
    // 下面會編譯錯誤
    // unique_ptr<Cat> pCat5 = pCat4;
    // 但可以透過move去轉移擁有權,move下次再介紹
    unique_ptr<Cat> pCat6 = move(pCat4); // cat4就不能用了

    // move也能將unique_ptr轉成shared_ptr,但不能將shared_ptr轉成unique_ptr
    shared_ptr<Cat> pCat7 = move(pCat6);

    return 0;
}

weak_ptr

weak_ptr是搭配shared_ptr,用來檢查資源被釋放了沒,並不影響資源的記數,參考下面例子

int main(int argc, char const *argv[])
{
    weak_ptr<Cat> wp(pCat7);
    cout << "pCat7 count: " << wp.use_count() << endl;
    if (wp.expired())
    {
        cout << "wp was expired\n";
    }
    else
    {
        cout << "wp was not expired\n";
    }
    
    // 手動釋放
    pCat7.reset();

    if (wp.expired())
    {
        cout << "wp was expired\n";
    }
    else
    {
        cout << "wp was not expired\n";
    }

    return 0;
}

上一篇
排序演算法 3
下一篇
資源管理 右值
系列文
C++ 實務基礎經驗25
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言