7 智能指针之 unique_ptr 的使用
在上一篇文章中,我们深入探讨了 C++ 中的移动语义与完美转发,特别是移动构造与移动赋值操作。而在这一篇中,我们将专注于 C++11 引入的智能指针之一:unique_ptr。unique_ptr 是一种用来管理动态分配内存的智能指针,它可以自动管理资源的生命周期,从而避免内存泄露。
什么是 unique_ptr
unique_ptr 是一种独占所有权的智能指针。它所指向的对象只能由一个 unique_ptr 拥有,不能被复制,但可以通过移动操作来转移所有权。这使得 unique_ptr 成为资源管理的安全方式。
unique_ptr 的基本使用
下面,我们来看一下 unique_ptr 的基本用法。
创建 unique_ptr
使用 std::make_unique 创建 unique_ptr 是一种推荐的方式:
#include <iostream>
#include <memory>
class Example {
public:
    Example() { std::cout << "Example created\n"; }
    ~Example() { std::cout << "Example destroyed\n"; }
    void show() { std::cout << "Showing Example\n"; }
};
int main() {
    // 创建 unique_ptr
    std::unique_ptr<Example> ptr = std::make_unique<Example>();
    ptr->show();
    
    // ptr 超出作用域时,Example 会被自动销毁
    return 0;
}
在这个示例中,我们使用 std::make_unique<Example>() 来创建 unique_ptr。当 ptr 超出作用域时,Example 对象会被自动销毁,避免了手动调用 delete 的麻烦。
移动 unique_ptr
由于 unique_ptr 的所有权是独占的,无法复制,但可以通过移动来转移所有权。
#include <iostream>
#include <memory>
class Example {
public:
    Example() { std::cout << "Example created\n"; }
    ~Example() { std::cout << "Example destroyed\n"; }
};
int main() {
    std::unique_ptr<Example> ptr1 = std::make_unique<Example>();
    // 移动 ptr1 到 ptr2
    std::unique_ptr<Example> ptr2 = std::move(ptr1);
    
    if (!ptr1) {
        std::cout << "ptr1 is now empty\n";
    }
    
    // ptr2 现在拥有 Example 的所有权
    return 0;
}
在这个示例中,std::move(ptr1) 被用于将 ptr1 的所有权转移到 ptr2。一旦移动后,ptr1 将变为 nullptr,因此可以在后续代码中检查它的状态。
自定义删除器
unique_ptr 还允许我们自定义删除器,这在处理资源时非常有用。
#include <iostream>
#include <memory>
void customDeleter(Example* e) {
    std::cout << "Custom deleting Example\n";
    delete e;
}
int main() {
    std::unique_ptr<Example, decltype(&customDeleter)> ptr(new Example(), customDeleter);
    return 0;
}
在上面的代码中,我们定义了一个自定义删除器 customDeleter,并使用 decltype 指定了 unique_ptr 的删除器类型。当 ptr 超出作用域时,将调用自定义删除器来释放内存。
注意事项
- 不可复制:
unique_ptr不能被复制,必须使用std::move来转移所有权。 - 避免循环引用:在使用 
unique_ptr的时候要注意,如果两个对象相互持有unique_ptr,将导致内存泄露。 - 适用于动态分配的资源:
unique_ptr主要用于管理动态分配的资源。 
小结
在这一篇中,我们详细地探讨了 C++ 中的 unique_ptr,并且通过多个示例展示了它的创建、移动和自定义删除器的使用。unique_ptr 的引入大大简化了内存管理,让我们可以更安全地管理动态分配的资源。
接下来的篇章中,我们将继续介绍其他智能指针,包括 shared_ptr 和 weak_ptr,并比较它们各自的用途与特点。希望大家能继续关注学习。
