中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中unique_ptr如何使用

發布時間:2021-07-22 14:53:37 來源:億速云 閱讀:178 作者:Leah 欄目:互聯網科技

本篇文章為大家展示了C++中unique_ptr如何使用,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

unique_ptr 是 C++ 11 提供的用于防止內存泄漏的智能指針中的一種實現,獨享被管理對象指針所有權的智能指針。unique_ptr對象包裝一個原始指針,并負責其生命周期。當該對象被銷毀時,會在其析構函數中刪除關聯的原始指針。
unique_ptr具有->和*運算符重載符,因此它可以像普通指針一樣使用。
查看下面的示例:

#include <iostream>
#include <memory>

struct Task {
    int mId;
    Task(int id ) :mId(id) {
        std::cout << "Task::Constructor" << std::endl;
    }
    ~Task() {
        std::cout << "Task::Destructor" << std::endl;
    }
};

int main()
{
    // 通過原始指針創建 unique_ptr 實例
    std::unique_ptr<Task> taskPtr(new Task(23));

    //通過 unique_ptr 訪問其成員
    int id = taskPtr->mId;
    std::cout << id << std::endl;

    return 0;
}

輸出:

Task::Constructor

Task::Destructor

unique_ptr <Task> 對象 taskPtr 接受原始指針作為參數。現在當main函數退出時,該對象超出作用范圍就會調用其析構函數,在unique_ptr對象taskPtr 的析構函數中,會刪除關聯的原始指針,這樣就不用專門delete Task對象了。
這樣不管函數正常退出還是異常退出(由于某些異常),也會始終調用taskPtr的析構函數。因此,原始指針將始終被刪除并防止內存泄漏。

unique_ptr 獨享所有權
unique_ptr對象始終是關聯的原始指針的唯一所有者。我們無法復制unique_ptr對象,它只能移動。
由于每個unique_ptr對象都是原始指針的唯一所有者,因此在其析構函數中它直接刪除關聯的指針,不需要任何參考計數。

創建一個空的 unique_ptr 對象
創建一個空的unique_ptr<int>對象,因為沒有與之關聯的原始指針,所以它是空的。

std::unique_ptr<int> ptr1;

檢查 unique_ptr 對象是否為空
有兩種方法可以檢查 unique_ptr 對象是否為空或者是否有與之關聯的原始指針。

// 方法1
if(!ptr1)
    std::cout<<"ptr1 is empty"<<std::endl;
// 方法2
if(ptr1 == nullptr)
    std::cout<<"ptr1 is empty"<<std::endl;

使用原始指針創建 unique_ptr 對象
要創建非空的 unique_ptr 對象,需要在創建對象時在其構造函數中傳遞原始指針,即:

std::unique_ptr<Task> taskPtr(new Task(22));

不能通過賦值的方法創建對象,下面的這句是錯誤的

// std::unique_ptr<Task> taskPtr2 = new Task(); // 編譯錯誤

使用 std::make_unique 創建 unique_ptr 對象 / C++14
std::make_unique<>() 是C++ 14 引入的新函數

std::unique_ptr<Task> taskPtr = std::make_unique<Task>(34);

獲取被管理對象的指針
使用get()·函數獲取管理對象的指針。

Task *p1 = taskPtr.get();

重置 unique_ptr 對象
在 unique_ptr 對象上調用reset()函數將重置它,即它將釋放delete關聯的原始指針并使unique_ptr 對象為空。

taskPtr.reset();

unique_ptr 對象不可復制
由于 unique_ptr 不可復制,只能移動。因此,我們無法通過復制構造函數或賦值運算符創建unique_ptr對象的副本。

// 編譯錯誤 : unique_ptr 不能復制
std::unique_ptr<Task> taskPtr3 = taskPtr2; // Compile error

// 編譯錯誤 : unique_ptr 不能復制
taskPtr = taskPtr2; //compile error

轉移 unique_ptr 對象的所有權
我們無法復制 unique_ptr 對象,但我們可以轉移它們。這意味著 unique_ptr 對象可以將關聯的原始指針的所有權轉移到另一個 unique_ptr 對象。讓我們通過一個例子來理解:

// 通過原始指針創建 taskPtr2
std::unique_ptr<Task> taskPtr2(new Task(55));
// 把taskPtr2中關聯指針的所有權轉移給taskPtr4
std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2);
// 現在taskPtr2關聯的指針為空
if(taskPtr2 == nullptr)
    std::cout<<"taskPtr2 is  empty"<<std::endl;

// taskPtr2關聯指針的所有權現在轉移到了taskPtr4中
if(taskPtr4 != nullptr)
    std::cout<<"taskPtr4 is not empty"<<std::endl;

// 會輸出55
std::cout<< taskPtr4->mId << std::endl;

std::move() 將把 taskPtr2 轉換為一個右值引用。因此,調用 unique_ptr 的移動構造函數,并將關聯的原始指針傳輸到 taskPtr4。在轉移完原始指針的所有權后, taskPtr2將變為空。

釋放關聯的原始指針
在 unique_ptr 對象上調用 release()將釋放其關聯的原始指針的所有權,并返回原始指針。這里是釋放所有權,并沒有delete原始指針,reset()會delete原始指針。

std::unique_ptr<Task> taskPtr5(new Task(55));
// 不為空
if(taskPtr5 != nullptr)
    std::cout<<"taskPtr5 is not empty"<<std::endl;
// 釋放關聯指針的所有權
Task * ptr = taskPtr5.release();
// 現在為空
if(taskPtr5 == nullptr)
    std::cout<<"taskPtr5 is empty"<<std::endl;

完整示例程序
#include <iostream>
#include <memory>

struct Task {
    int mId;
    Task(int id ) :mId(id) {
        std::cout<<"Task::Constructor"<<std::endl;
    }
    ~Task() {
        std::cout<<"Task::Destructor"<<std::endl;
    }
};

int main()
{
    // 空對象 unique_ptr
    std::unique_ptr<int> ptr1;

    // 檢查 ptr1 是否為空
    if(!ptr1)
        std::cout<<"ptr1 is empty"<<std::endl;

    // 檢查 ptr1 是否為空
    if(ptr1 == nullptr)
        std::cout<<"ptr1 is empty"<<std::endl;

    // 不能通過賦值初始化unique_ptr
    // std::unique_ptr<Task> taskPtr2 = new Task(); // Compile Error

    // 通過原始指針創建 unique_ptr
    std::unique_ptr<Task> taskPtr(new Task(23));

    // 檢查 taskPtr 是否為空
    if(taskPtr != nullptr)
        std::cout<<"taskPtr is  not empty"<<std::endl;

    // 訪問 unique_ptr關聯指針的成員
    std::cout<<taskPtr->mId<<std::endl;

    std::cout<<"Reset the taskPtr"<<std::endl;
    // 重置 unique_ptr 為空,將刪除關聯的原始指針
    taskPtr.reset();

    // 檢查是否為空 / 檢查有沒有關聯的原始指針
    if(taskPtr == nullptr)
        std::cout<<"taskPtr is  empty"<<std::endl;

    // 通過原始指針創建 unique_ptr
    std::unique_ptr<Task> taskPtr2(new Task(55));

    if(taskPtr2 != nullptr)
        std::cout<<"taskPtr2 is  not empty"<<std::endl;

    // unique_ptr 對象不能復制
    //taskPtr = taskPtr2; //compile error
    //std::unique_ptr<Task> taskPtr3 = taskPtr2;

    {
        // 轉移所有權(把unique_ptr中的指針轉移到另一個unique_ptr中)
        std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2);
        // 轉移后為空
        if(taskPtr2 == nullptr)
            std::cout << "taskPtr2 is  empty" << std::endl;
        // 轉進來后非空
        if(taskPtr4 != nullptr)
            std::cout<<"taskPtr4 is not empty"<<std::endl;

        std::cout << taskPtr4->mId << std::endl;

        //taskPtr4 超出下面這個括號的作用于將delete其關聯的指針
    }

    std::unique_ptr<Task> taskPtr5(new Task(66));

    if(taskPtr5 != nullptr)
        std::cout << "taskPtr5 is not empty" << std::endl;

    // 釋放所有權
    Task * ptr = taskPtr5.release();

    if(taskPtr5 == nullptr)
        std::cout << "taskPtr5 is empty" << std::endl;

    std::cout << ptr->mId << std::endl;

    delete ptr;

    return 0;
}

輸出:

ptr1 is empty
ptr1 is empty
Task::Constructor
taskPtr is  not empty
23
Reset the taskPtr
Task::Destructor
taskPtr is  empty
Task::Constructor
taskPtr2 is  not empty
taskPtr2 is  empty
taskPtr4 is not empty
55
Task::Destructor
Task::Constructor
taskPtr5 is not empty
taskPtr5 is empty
66
Task::Destructor

總結
new出來的對象是位于堆內存上的,必須調用delete才能釋放其內存。
unique_ptr 是一個裝指針的容器,且擁有關聯指針的唯一所有權,作為普通變量使用時系統分配對象到棧內存上,超出作用域時會自動析構,unique_ptr對象的析構函數中會delete其關聯指針,這樣就相當于替我們執行了delete堆內存上的對象。

成員函數    作用
reset()    重置unique_ptr為空,delete其關聯的指針。
release()    不delete關聯指針,并返回關聯指針。釋放關聯指針的所有權,unique_ptr為空。
get()    僅僅返回關聯指針
unique_ptr不能直接復制,必須使用std::move()轉移其管理的指針,轉移后原 unique_ptr 為空。std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2);

創建unique_ptr對象有兩種方法:

//C++11: 
std::unique_ptr<Task> taskPtr(new Task(23));
//C++14: 
std::unique_ptr<Task> taskPtr = std::make_unique<Task>(34);

上述內容就是C++中unique_ptr如何使用,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

资阳市| 云龙县| 西乡县| 奉新县| 桐梓县| 安宁市| 乳源| 萨嘎县| 江门市| 西乡县| 平陆县| 曲阳县| 瑞丽市| 宁乡县| 漾濞| 嘉鱼县| 囊谦县| 六安市| 通渭县| 峡江县| 巫溪县| 剑川县| 东丰县| 米易县| 华阴市| 乌兰察布市| 九龙县| 康定县| 清涧县| 双桥区| 原阳县| 楚雄市| 武穴市| 章丘市| 新巴尔虎左旗| 凤台县| 鄂尔多斯市| 东台市| 兴和县| 织金县| 昌图县|