獨占指針(unique_ptr
)是C++11標準引入的一種智能指針,用于獨占管理動態分配對象的生命周期。unique_ptr
確保對象在同一時間只有一個所有者,防止對象被多個指針共享。下面是unique_ptr
的實現原理及其內存管理機制。
unique_ptr
的基本原理
-
獨占所有權:
unique_ptr
獨占對象的所有權,不能被復制,但可以移動。- 通過移動語義,可以將所有權從一個
unique_ptr
轉移到另一個。
-
自動內存管理:
- 當
unique_ptr
被銷毀時,它所管理的對象也會被銷毀,自動釋放內存。
- 當
實現原理
-
基本結構:
unique_ptr
是一個模板類,包含一個原始指針和一個刪除器。- 刪除器是一個可調用對象(如函數指針、函數對象或
std::default_delete
),用于在unique_ptr
銷毀時釋放對象。
-
構造與析構:
- 構造函數:接受一個原始指針,默認使用
std::default_delete
作為刪除器。 - 析構函數:調用刪除器釋放對象。
- 構造函數:接受一個原始指針,默認使用
-
禁止復制:
unique_ptr
禁止復制構造和復制賦值操作。- 通過刪除復制構造函數和復制賦值操作符來實現。
-
移動語義:
- 允許移動構造和移動賦值操作。
- 通過移動構造和移動賦值操作符將所有權轉移到另一個
unique_ptr
。
代碼示例
#include <iostream>
#include <memory>class MyClass {
public:MyClass() { std::cout << "MyClass constructed\n"; }~MyClass() { std::cout << "MyClass destroyed\n"; }void sayHello() { std::cout << "Hello\n"; }
};int main() {std::unique_ptr<MyClass> ptr1(new MyClass());ptr1->sayHello();// std::unique_ptr<MyClass> ptr2 = ptr1; // 錯誤:不能復制 unique_ptrstd::unique_ptr<MyClass> ptr2 = std::move(ptr1); // 移動所有權if (!ptr1) {std::cout << "ptr1 is empty\n";}if (ptr2) {ptr2->sayHello();}return 0;
}
輸出結果
MyClass constructed
Hello
ptr1 is empty
Hello
MyClass destroyed
內存管理機制
-
獨占所有權:
unique_ptr
在同一時間只能有一個所有者,禁止復制操作。- 通過移動操作將所有權轉移。
-
自動釋放內存:
- 當
unique_ptr
超出作用域或被銷毀時,自動調用刪除器釋放對象內存。
- 當
總結
unique_ptr
提供了一種安全的、自動的內存管理方式,確保對象不會被多個指針共享。- 它通過禁止復制和允許移動操作實現獨占所有權。
- 使用刪除器在
unique_ptr
銷毀時釋放對象內存,防止內存泄漏。
代碼實現
這里是一個簡單的unique_ptr
的實現原理代碼示例。這個示例包含了unique_ptr
的核心功能,包括獨占所有權、移動語義以及自動內存管理。
#include <iostream>
#include <utility> // for std::movetemplate<typename T>
class UniquePtr {
private:T* ptr; // 原始指針public:// 構造函數explicit UniquePtr(T* p = nullptr) : ptr(p) {}// 禁止復制構造函數UniquePtr(const UniquePtr&) = delete;// 禁止復制賦值操作符UniquePtr& operator=(const UniquePtr&) = delete;// 移動構造函數UniquePtr(UniquePtr&& other) noexcept : ptr(other.ptr) {other.ptr = nullptr; // 將源指針置為空}// 移動賦值操作符UniquePtr& operator=(UniquePtr&& other) noexcept {if (this != &other) {delete ptr; // 釋放當前持有的資源ptr = other.ptr; // 轉移所有權other.ptr = nullptr; // 將源指針置為空}return *this;}// 析構函數~UniquePtr() {delete ptr; // 釋放資源}// 重載 * 操作符T& operator*() const {return *ptr;}// 重載 -> 操作符T* operator->() const {return ptr;}// 獲取原始指針T* get() const {return ptr;}// 釋放所有權并返回原始指針T* release() {T* temp = ptr;ptr = nullptr;return temp;}// 重新設置指針void reset(T* p = nullptr) {if (ptr != p) {delete ptr; // 釋放當前持有的資源ptr = p; // 設置新的指針}}
};class MyClass {
public:MyClass() { std::cout << "MyClass constructed\n"; }~MyClass() { std::cout << "MyClass destroyed\n"; }void sayHello() { std::cout << "Hello\n"; }
};int main() {UniquePtr<MyClass> ptr1(new MyClass());ptr1->sayHello();// UniquePtr<MyClass> ptr2 = ptr1; // 錯誤:不能復制 unique_ptrUniquePtr<MyClass> ptr2 = std::move(ptr1); // 移動所有權if (!ptr1.get()) {std::cout << "ptr1 is empty\n";}if (ptr2.get()) {ptr2->sayHello();}return 0;
}
代碼說明
-
構造函數:
UniquePtr(T* p = nullptr) : ptr(p) {}
:構造函數初始化原始指針。
-
禁止復制:
UniquePtr(const UniquePtr&) = delete;
:禁止復制構造函數。UniquePtr& operator=(const UniquePtr&) = delete;
:禁止復制賦值操作符。
-
移動語義:
UniquePtr(UniquePtr&& other) noexcept
:移動構造函數,從其他UniquePtr
轉移所有權,并將源指針置空。UniquePtr& operator=(UniquePtr&& other) noexcept
:移動賦值操作符,從其他UniquePtr
轉移所有權,并將源指針置空。
-
析構函數:
~UniquePtr()
:析構函數釋放資源。
-
智能指針接口:
T& operator*() const
:重載解引用操作符。T* operator->() const
:重載箭頭操作符。T* get() const
:返回原始指針。T* release()
:釋放所有權并返回原始指針。void reset(T* p = nullptr)
:重新設置指針,釋放當前持有的資源。
輸出結果
MyClass constructed
Hello
ptr1 is empty
Hello
MyClass destroyed
總結
UniquePtr
確保對象在同一時間只有一個所有者,防止多個指針共享。- 通過移動語義,可以將所有權從一個
UniquePtr
轉移到另一個。 UniquePtr
自動管理對象生命周期,當智能指針超出作用域時自動釋放資源。