2024年12月23日 星期一

vector、unique_ptr、shared_ptr 的區別

在 C++ 中,std::vectorstd::unique_ptrstd::shared_ptr 是三個不同的工具,雖然它們有不同的用途,但可以互相結合使用來管理動態記憶體。讓我們來詳細解釋它們的區別和用法。

1. std::vector

std::vector 是 C++ 標準庫中的動態陣列容器,它允許你儲存任意數量的元素,而且容器的大小會隨著元素的增加或減少自動調整。std::vector 會管理記憶體分配和釋放,並且提供快速隨機存取。

特點:

  • 動態大小:當你向 std::vector 中新增元素時,它會自動調整容量。
  • 連續記憶體std::vector 儲存在連續的記憶體位置,這使得它對於隨機存取操作非常高效。
  • 自動管理記憶體std::vector 會自動處理記憶體的分配和釋放。

範例:

#include <iostream>
#include <vector> int main() { std::vector<int> vec; vec.push_back(10); vec.push_back(20); vec.push_back(30); for (int num : vec) { std::cout << num << std::endl; } return 0; }

2. std::unique_ptr

std::unique_ptr 是 C++11 引入的智能指標,它是 唯一擁有 物件的指標,也就是說,當 unique_ptr 被銷毀或移動時,它所指向的物件會自動被釋放。unique_ptr 不允許拷貝,只允許移動,這可以確保物件只有一個所有者,避免了多重釋放的問題。

特點:

  • 唯一擁有者std::unique_ptr 保證它是唯一擁有指向的物件的指標,無法拷貝。
  • 自動釋放記憶體:當 unique_ptr 超出作用域時,它會自動釋放記憶體。
  • 移動語義:可以使用 std::move()unique_ptr 移動給另一個 unique_ptr,這樣會將所有權轉移給另一個指標。

範例:

#include <iostream>
#include <memory> class MyClass { public: void sayHello() { std::cout << "Hello from MyClass!" << std::endl; } }; int main() { std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(); ptr1->sayHello(); // 不允許拷貝,但可以移動 std::unique_ptr<MyClass> ptr2 = std::move(ptr1); // ptr1 現在為 nullptr return 0; }

3. std::shared_ptr

std::shared_ptr 是 C++11 引入的另一種智能指標,它允許多個指標共享對同一物件的擁有權。當最後一個 shared_ptr 被銷毀時,物件會被釋放。shared_ptr 使用引用計數來追蹤有多少個 shared_ptr 指向同一個物件。

特點:

  • 共享所有權:多個 shared_ptr 可以指向同一物件,它們共享所有權,當最後一個 shared_ptr 被銷毀時,物件會被釋放。
  • 引用計數:每次創建一個新的 shared_ptr 時,內部會維護一個引用計數,當引用計數降到 0 時,物件才會被銷毀。
  • 可以拷貝和移動shared_ptr 可以拷貝,這會增加引用計數。

範例:

#include <iostream>
#include <memory> class MyClass { public: void sayHello() { std::cout << "Hello from MyClass!" << std::endl; } }; int main() { std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(); ptr1->sayHello(); // 拷貝 shared_ptr,引用計數會增加 std::shared_ptr<MyClass> ptr2 = ptr1; ptr2->sayHello(); // 當最後一個 shared_ptr 被銷毀時,MyClass 物件會自動釋放 return 0; }

區別總結:

特性/指標類型std::vectorstd::unique_ptrstd::shared_ptr
用途儲存動態數據的容器(如陣列)管理動態分配的單一物件(唯一擁有者)管理動態分配的物件,允許多個擁有者
記憶體管理自動管理記憶體自動釋放記憶體依靠引用計數自動釋放記憶體
是否允許拷貝允許拷貝不允許拷貝,只允許移動允許拷貝和移動,增加引用計數
是否多重擁有無多重擁有(只能擁有元素的指標)不能多重擁有(只能有一個 unique_ptr支援多重擁有(多個 shared_ptr 指向同一物件)
當物件銷毀時vector 被銷毀時,容器內的所有物件也會被銷毀unique_ptr 被銷毀時,它所擁有的物件會被釋放當最後一個 shared_ptr 被銷毀時,物件才會被釋放

如何結合使用它們:

  • std::vectorstd::unique_ptr:你可以將 std::unique_ptr 儲存到 std::vector 中,用來管理一系列動態分配的物件。例如,儲存一組指向不同物件的 unique_ptr

    #include <vector>
    #include <memory> class MyClass { public: void sayHello() { std::cout << "Hello from MyClass!" << std::endl; } }; int main() { std::vector<std::unique_ptr<MyClass>> vec; vec.push_back(std::make_unique<MyClass>()); vec[0]->sayHello(); return 0; }
  • std::vectorstd::shared_ptr:你也可以將 std::shared_ptr 儲存到 std::vector 中,這樣可以共享物件的所有權,並在需要時讓多個指標共享同一個物件。

    #include <vector>
    #include <memory> class MyClass { public: void sayHello() { std::cout << "Hello from MyClass!" << std::endl; } }; int main() { std::vector<std::shared_ptr<MyClass>> vec; vec.push_back(std::make_shared<MyClass>()); vec[0]->sayHello(); return 0; }

總結:

  • std::vector 用於動態數據儲存,尤其是需要動態調整大小的情況。
  • std::unique_ptr 用於管理單一物件的所有權,確保記憶體自動釋放且不會有多重所有者。
  • std::shared_ptr 用於多個擁有者共享同一物件,通過引用計數管理記憶體的釋放。

沒有留言:

張貼留言