# unique_ptr

URL: https://caijiao.org/cpp/stl/unique_ptr
Source: docs/cpp/stl/unique_ptr.md
Description: 本节介绍 C++ 中的 'unique_ptr' 智能指针，帮助理解如何使用 'unique_ptr' 管理动态内存，避免内存泄漏和资源管理问题。

`unique_ptr` 是 C++11 引入的智能指针，属于智能指针中的一种，专门用于管理动态分配的内存。它确保所管理的对象在指针超出作用域时会自动销毁，从而避免内存泄漏。与传统的裸指针不同，`unique_ptr` 提供了更安全和自动化的内存管理机制。

## unique_ptr 的基本特性

1. **唯一所有权**：`unique_ptr` 拥有它所指向对象的唯一所有权。当 `unique_ptr` 被销毁时，它所指向的对象也会被销毁。
2. **不可复制**：由于 `unique_ptr` 具有唯一所有权，它不能被复制。只能通过移动语义将 `unique_ptr` 从一个变量转移到另一个变量。
3. **自动销毁**：当 `unique_ptr` 超出作用域时，它会自动释放所管理的对象，无需手动调用 `delete`。

## unique_ptr 的创建与使用

`unique_ptr` 可以通过 `std::make_unique` 或直接使用构造函数来创建。

### 示例：创建和使用 unique_ptr

```cpp
#include <iostream>
#include <memory>  // 引入 unique_ptr 所在的头文件

using namespace std;

class MyClass {
public:
    MyClass() { cout << "MyClass Constructor\n"; }
    ~MyClass() { cout << "MyClass Destructor\n"; }
    void show() { cout << "Hello, MyClass!\n"; }
};

int main() {
    // 使用 make_unique 创建 unique_ptr
    unique_ptr<MyClass> ptr1 = make_unique<MyClass>();
    ptr1->show();  // 调用 MyClass 的成员函数

    // 使用 new 创建 unique_ptr
    unique_ptr<MyClass> ptr2(new MyClass());
    ptr2->show();  // 调用 MyClass 的成员函数

    // unique_ptr 在作用域结束时自动释放内存
    return 0;
}
````

输出：

```
MyClass Constructor
Hello, MyClass!
MyClass Constructor
Hello, MyClass!
MyClass Destructor
MyClass Destructor
```

在这个例子中，我们通过 `make_unique` 和 `new` 创建了两个 `unique_ptr` 对象。`unique_ptr` 在作用域结束时会自动释放它所管理的内存。

## 移动语义与 unique\_ptr

`unique_ptr` 不允许复制，但允许转移所有权。使用移动语义，可以将 `unique_ptr` 从一个变量转移到另一个变量，原来的 `unique_ptr` 会变为空指针。

### 示例：移动 unique\_ptr

```cpp
#include <iostream>
#include <memory>

using namespace std;

class MyClass {
public:
    MyClass() { cout << "MyClass Constructor\n"; }
    ~MyClass() { cout << "MyClass Destructor\n"; }
    void show() { cout << "Hello, MyClass!\n"; }
};

int main() {
    unique_ptr<MyClass> ptr1 = make_unique<MyClass>();
    ptr1->show();
    
    // 移动 ptr1 的所有权到 ptr2
    unique_ptr<MyClass> ptr2 = move(ptr1);
    ptr2->show();

    // ptr1 现在为空指针
    if (!ptr1) {
        cout << "ptr1 is empty\n";  // 输出 ptr1 is empty
    }

    return 0;
}
```

输出：

```
MyClass Constructor
Hello, MyClass!
MyClass Constructor
Hello, MyClass!
ptr1 is empty
MyClass Destructor
MyClass Destructor
```

在此示例中，`ptr1` 的所有权被移动到 `ptr2`，并且 `ptr1` 被置为空指针。这样就避免了内存泄漏，同时仍然保证了内存的自动销毁。

## unique\_ptr 的常见操作

### 获取裸指针

虽然 `unique_ptr` 管理内存，但在某些情况下，可能需要获取它所指向对象的裸指针。可以使用 `get()` 成员函数来实现这一点。

```cpp
#include <iostream>
#include <memory>

using namespace std;

class MyClass {
public:
    MyClass() { cout << "MyClass Constructor\n"; }
    ~MyClass() { cout << "MyClass Destructor\n"; }
    void show() { cout << "Hello, MyClass!\n"; }
};

int main() {
    unique_ptr<MyClass> ptr = make_unique<MyClass>();
    
    // 获取裸指针并使用它
    MyClass* rawPtr = ptr.get();
    rawPtr->show();
    
    // unique_ptr 会在作用域结束时释放内存
    return 0;
}
```

输出：

```
MyClass Constructor
Hello, MyClass!
MyClass Destructor
```

### 重置 unique\_ptr

`reset()` 方法可以用来重置 `unique_ptr`，释放当前管理的对象，并使 `unique_ptr` 成为一个空指针。如果提供一个新的对象，`reset()` 会让 `unique_ptr` 管理这个新的对象。

```cpp
#include <iostream>
#include <memory>

using namespace std;

class MyClass {
public:
    MyClass() { cout << "MyClass Constructor\n"; }
    ~MyClass() { cout << "MyClass Destructor\n"; }
    void show() { cout << "Hello, MyClass!\n"; }
};

int main() {
    unique_ptr<MyClass> ptr = make_unique<MyClass>();
    ptr->show();

    // 重置 unique_ptr，释放当前对象
    ptr.reset();
    if (!ptr) {
        cout << "ptr is reset and empty\n";  // 输出 ptr is reset and empty
    }

    return 0;
}
```

输出：

```
MyClass Constructor
Hello, MyClass!
ptr is reset and empty
MyClass Destructor
```

## 总结

* `unique_ptr` 是 C++11 引入的智能指针，用于管理动态分配的内存。
* 它有独占所有权，确保内存的自动释放，避免内存泄漏。
* `unique_ptr` 不能复制，但支持移动语义。
* `unique_ptr` 提供了 `reset()`、`get()` 等操作，用于管理对象的生命周期。

通过使用 `unique_ptr`，可以显著减少内存管理错误，简化代码的内存管理部分，提升程序的安全性与可维护性。
