C++ 智慧指標詳解: std::unique_ptr 和 std::shared_ptr

非法关键字發表於2024-09-27

C++11引入了智慧指標,它們是管理動態分配記憶體的強大工具。本文將詳細介紹兩種最常用的智慧指標: std::unique_ptrstd::shared_ptr

std::unique_ptr

概述

std::unique_ptr 是一種獨佔所有權的智慧指標。它確保一個物件只能被一個 unique_ptr 所擁有,這意味著不能複製 unique_ptr,只能移動它。

主要特性

  1. 獨佔所有權: 一個 unique_ptr 不能被複制,只能被移動。
  2. 自動釋放: 當 unique_ptr 離開作用域時,它所管理的物件會被自動刪除。
  3. 零開銷: 在大多數操作中, unique_ptr 與原始指標的效能相當。
  4. 自定義刪除器: 可以指定自定義的刪除方式。

示例程式碼

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "MyClass constructed\n"; }
    ~MyClass() { std::cout << "MyClass destructed\n"; }
    void doSomething() { std::cout << "Doing something\n"; }
};

int main() {
    // 建立unique_ptr
    std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
    
    // 使用->訪問成員
    ptr1->doSomething();
    
    // 無法複製unique_ptr
    // std::unique_ptr<MyClass> ptr2 = ptr1; // 編譯錯誤
    
    // 可以移動unique_ptr
    std::unique_ptr<MyClass> ptr2 = std::move(ptr1);
    
    // ptr1現在為空
    if (ptr1 == nullptr) {
        std::cout << "ptr1 is null\n";
    }
    
    // ptr2現在擁有物件
    ptr2->doSomething();
    
    // 離開作用域時,ptr2自動刪除物件
}

std::shared_ptr

概述

std::shared_ptr 是一種共享所有權的智慧指標。多個 shared_ptr 可以指向同一個物件,物件的記憶體會在最後一個引用被銷燬時釋放。

主要特性

  1. 共享所有權: 多個 shared_ptr 可以指向同一個物件。
  2. 引用計數: 內部維護一個引用計數,當計數降為0時刪除物件。
  3. 執行緒安全: 引用計數的增減是原子操作,但物件本身的訪問不是執行緒安全的。
  4. 可以從 this 指標建立: 可以安全地從一個物件的成員函式中建立指向 this 的 shared_ptr

示例程式碼

#include <iostream>
#include <memory>

class SharedClass : public std::enable_shared_from_this<SharedClass> {
public:
    SharedClass() { std::cout << "SharedClass constructed\n"; }
    ~SharedClass() { std::cout << "SharedClass destructed\n"; }
    
    std::shared_ptr<SharedClass> getShared() {
        return shared_from_this();
    }
};

int main() {
    // 建立shared_ptr
    auto ptr1 = std::make_shared<SharedClass>();
    
    {
        // 建立另一個指向同一物件的shared_ptr
        std::shared_ptr<SharedClass> ptr2 = ptr1;
        
        std::cout << "使用計數: " << ptr1.use_count() << std::endl; // 輸出 2
        
        // 從物件內部獲取shared_ptr
        auto ptr3 = ptr1->getShared();
        std::cout << "使用計數: " << ptr1.use_count() << std::endl; // 輸出 3
        
        // ptr2和ptr3離開作用域,但物件不會被刪除
    }
    
    std::cout << "使用計數: " << ptr1.use_count() << std::endl; // 輸出 1
    
    // ptr1離開作用域,物件被刪除
}

比較 unique_ptr 和 shared_ptr

特性 std::unique_ptr std::shared_ptr
所有權 獨佔 共享
複製 不允許 允許
移動 允許 允許
引用計數
效能開銷 幾乎為零 有一定開銷
記憶體使用 與原始指標相同 額外記憶體用於控制塊
執行緒安全 不適用 引用計數操作是安全的
迴圈引用 不會發生 可能發生,需要注意

最佳實踐

  1. 優先使用 std::unique_ptr,除非確實需要共享所有權。
  2. 使用 std::make_uniquestd::make_shared 來建立智慧指標。
  3. 避免使用裸指標,儘可能使用智慧指標。
  4. 注意避免 std::shared_ptr 的迴圈引用問題,必要時使用 std::weak_ptr
  5. 在類的公共介面中返回 std::unique_ptr 來轉移所有權。
  6. 在需要共享但不參與所有權的場景中使用 std::weak_ptr

std::unique_ptrstd::shared_ptr 是C++中管理動態記憶體的強大工具。正確使用這些智慧指標可以大大減少記憶體洩漏的風險,提高程式碼的安全性和可維護性。理解它們的特性和適用場景對於編寫高質量的C++程式至關重要。

相關文章