banner
Matrix

Matrix

Abyss
email
github

Petty C++ 指標

智能指標#

C++ 中的智能指標是一種用於管理動態分配的物件的指標。它們提供了自動記憶體回收的功能,可以幫助避免記憶體洩漏和懸空指標的問題。C++ 標準庫提供了兩種主要的智能指標:std::unique_ptrstd::shared_ptr

  1. std::unique_ptr
    std::unique_ptr是一種獨佔所有權的智能指標。它確保只有一個指標可以訪問給定的資源。當std::unique_ptr超出範圍或被刪除時,它會自動釋放所管理的物件。它不能被複製,但可以通過移動語義傳遞所有權。使用std::make_unique函數可以方便地創建std::unique_ptr物件。
{
  std::unique_ptr<int> ptr = std::make_uniqure<int>(42);
  std::cout << *ptr << std::endl;
}

// ptr 超出範圍後,其管理的物件會被自動釋放
  1. std::shared_ptr
    std::shared_ptr是一種共享所有權的智能指標。它可以被多個指標共享,並且會跟踪有多少個指標引用了給定的資源。只有當最後一個std::shared_ptr超出範圍或被刪除時,才會釋放所管理的物件。它可以通過複製來共享所有權,也可以通過移動語義傳遞所有權。使用std::make_shared函數可以方便地創建std::shared_ptr物件。

{
std::unique_ptr ptr1 = std::make_uniqure(42);
std::unique_ptr ptr2 = ptr1; // 共享所有權
}

//ptr1 和 ptr2 超出範圍後,其管理的物件會被自動釋放

智能指標的使用可以有效地管理動態分配的物件,避免記憶體洩漏和懸空指標的問題。但需要注意,智能指標並不能解決所有的記憶體管理問題,例如循環引用可能導致資源無法釋放。因此,在使用智能指標時,仍然需要謹慎設計和管理物件的生命週期。

關於共享指標,以 std::make_shared<Chunk>(position) 為例#

std::make_shared<Chunk>(position) 是一個使用 std::make_shared 函數創建 Chunk 物件的語法。

具體來說,這行程式碼使用了尖括號 <Chunk> 來指定模板參數,告訴 std::make_shared 函數我們要創建的物件的類型是 Chunk。然後,括號中的 position 是傳遞給 Chunk 建構函數的參數。

std::make_shared 是一個模板函數,它的定義如下:

template<typenameT, typename... Args>
shared_ptr<T> make_shared(Args&&... args);

它接受一個可變數量的參數 Args&&... args,這些參數將被傳遞給 T 類型的建構函數來創建物件。在這個例子中,TChunk 類型,Argsposition 的類型。

std::make_shared 函數返回一個 shared_ptr<T> 類型的共享指標,它指向通過傳遞的參數建構的 T 類型物件。

因此,std::make_shared<Chunk>(position) 這行程式碼的作用是創建一個 Chunk 類型的物件,並使用共享指標來管理該物件的生命週期。同時,將 position 作為參數傳遞給 Chunk 的建構函數,以便在創建物件時進行初始化。

實際上,std::make_shared 主要用於構造新的物件。它會在堆上動態分配記憶體,並使用傳遞的參數來調用物件的建構函數

如果有一個已經存在的實例,並且想要將其包裝在一個共享指標中進行管理,可以使用 std::shared_ptr 的建構函數或 std::make_shared 的變體來實現。

使用 std::shared_ptr 的建構函數可以將一個已經存在的指標包裝成共享指標。#

例如:

Chunk* existingChunk = newChunk(position);
std::shared_ptr<Chunk> sharedChunk(existingChunk);

在這個例子中,existingChunk 是一個已經存在的 Chunk 物件的指標,通過將它傳遞給 std::shared_ptr 的建構函數,可以創建一個共享指標 sharedChunk 來管理該物件的生命週期。

在這種情況下,不應該繼續使用 existingChunk,因為一旦 sharedChunk 被銷毀(或者最後一個擁有它的共享指標被銷毀),它指向的記憶體會被自動釋放。如果在那之後嘗試訪問 existingChunk,將會導致未定義行為,比如訪問已經釋放的記憶體。

不推薦的!

另一種方法是使用 std::make_shared 的變體,即 std::allocate_shared

Chunk* existingChunk = newChunk(position);
std::shared_ptr<Chunk> sharedChunk = std::allocate_shared<Chunk>(std::allocator<Chunk>(), *existingChunk);

在這個例子中,使用 std::allocate_shared<Chunk>(std::allocator<Chunk>(), *existingChunk) 會創建一個新的 Chunk 實例,並且這個新實例是通過複製 existingChunk 指向的物件來初始化的。這裡並沒有發生將普通指標 existingChunk 轉換為共享指標的行為,而是發生了物件的複製。std::allocate_shared 使用提供的物件(即 *existingChunk)作為複製建構函數的參數來創建新物件,並由返回的共享指標管理。

通過 std::allocate_shared 創建一個物件的副本並同時保留原始指標指向的物件 —— 通常是不推薦的行為。這種做法會導致以下幾個問題:

  1. 記憶體管理複雜化:這種方法創建了兩個獨立的物件實例,一個由原始指標管理,另一個由共享指標管理。這就需要你分別管理這兩個物件的生命週期,增加了記憶體洩漏的風險。

  2. 設計意圖不明確:智能指標(如 std::shared_ptr)的引入主要是為了簡化記憶體管理,通過自動管理物件的生命週期來減少記憶體洩漏和懸垂指標的風險。通過複製物件而不是接管原始指標,你實際上沒有利用智能指標的主要優勢。

  3. 效能開銷:複製物件可能涉及顯著的效能開銷,尤其是當物件較大或複製操作代價高昂時。如果沒有必要創建物件的副本,這種開銷是可以避免的。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。