unique_ptr 智能指针详解

目录

std::unique_ptr:

unique_ptr独占所有权:

unique_ptr不要使用 delete 或 delete[]:

unique_ptr避免裸指针和 release 的滥用

unique_ptr自定义删除器


std::unique_ptr:

是 C++ 标准库中的一个智能指针类型,用于管理动态分配的资源,如堆上的对象。std::unique_ptr 拥有其所指向的资源的独占所有权,这意味着同一时间只能有一个 std::unique_ptr 指向该资源。如果需要转移 std::unique_ptr 的所有权,可以使用以下几种方式:

  1. 移动语义(Move Semantics): 通过移动构造函数和移动赋值操作符,你可以将一个 std::unique_ptr 的所有权转移到另一个。移动操作会使原来的指针变为 null,同时将所有权转移到新的指针上。这是一种高效的方式,因为它只涉及指针的重新指向,而不需要进行资源的拷贝或析构。

    std::unique_ptr ptr1 = std::make_unique(42); std::unique_ptr ptr2 = std::move(ptr1); // 转移所有权

  2. 使用 release 函数: std::unique_ptr 提供了 release 成员函数,它将指针从 std::unique_ptr 中释放,但并不会销毁资源。这可以用来将指针传递给其他代码,同时保留资源的所有权。

    std::unique_ptr ptr1 = std::make_unique(42); int* rawPtr = ptr1.release(); // 释放所有权但不销毁资源 // 在适当的时候要手动释放资源,以免内存泄漏 delete rawPtr;

  3. 使用 reset 函数: std::unique_ptrreset 成员函数允许你改变它所拥有的资源。它会释放当前资源并接收一个新的资源指针。这也可以用于将所有权转移给另一个 std::unique_ptr

    std::unique_ptr ptr1 = std::make_unique(42); std::unique_ptr ptr2 = std::make_unique(99); ptr2.reset(ptr1.release()); // 释放 ptr2 的资源,将 ptr1 的资源转移给 ptr2

需要注意的是,转移所有权后,原来的 std::unique_ptr 将不再拥有资源,不应再次使用它。这些转移所有权的操作能够有效地管理资源的生命周期,避免资源泄漏和重复释放的问题。

unique_ptr独占所有权:

std::unique_ptr 是 C++ 标准库提供的一种智能指针类型,其特点是它独占所指向资源的所有权。这意味着在任何给定时间,只能有一个 std::unique_ptr 指向特定的资源。当 std::unique_ptr 被销毁或转移给另一个 std::unique_ptr 时,它所拥有的资源会被自动释放。

独占所有权带来了一些重要的好处和注意事项:

优点:

  1. 避免资源泄漏: 由于资源的所有权只能由一个 std::unique_ptr 拥有,所以当 std::unique_ptr 被销毁时,它会自动释放其所拥有的资源,避免了资源泄漏的风险。

  2. 防止悬挂指针: 由于只有一个 std::unique_ptr 拥有资源的所有权,所以在资源被释放后,不会留下悬挂指针,即指向已经无效的资源的指针。

  3. 清晰的所有权转移: 通过移动语义,你可以将资源的所有权从一个 std::unique_ptr 转移到另一个。这使得代码更清晰,避免了复杂的资源管理逻辑。

注意事项:

  1. 不能共享所有权: std::unique_ptr 不能直接与其他智能指针共享资源所有权。如果需要共享资源,应该使用 std::shared_ptr

  2. 移动语义的重要性: 移动语义是使用 std::unique_ptr 的关键。通过移动构造函数和移动赋值操作符,可以高效地转移资源的所有权。

  3. 不要手动释放资源: 不要手动使用 deletedelete[] 释放 std::unique_ptr 管理的资源,这会导致不可预测的行为。

  4. 适用于独占资源: std::unique_ptr 适用于需要独占资源的情况,比如动态分配的单个对象或数组,文件句柄等。

unique_ptr不要使用 delete 或 delete[]:

std::unique_ptr 是一种智能指针,它负责自动释放其所拥有的资源。因此,不应该手动使用 deletedelete[] 来释放 std::unique_ptr 管理的资源,否则可能会导致未定义行为。这是因为当 std::unique_ptr 的析构函数被调用时,它会自动使用正确的方式释放资源,包括调用适当的 deletedelete[]

以下是一个示例,展示了在使用 std::unique_ptr 时,不应手动使用 delete 的情况:

#include 
#include 

class MyClass {
public:
    MyClass() {
        std::cout << "MyClass constructor" << std::endl;
    }

    ~MyClass() {
        std::cout << "MyClass destructor" << std::endl;
    }
};

int main() {
    std::unique_ptr ptr = std::make_unique();

    // 错误示例:不要手动使用 delete
    // delete ptr.get();  // 不应手动释放资源

    return 0;
}

在这个示例中,我们创建了一个 std::unique_ptr,它管理一个 MyClass 的实例。std::unique_ptr 在其生命周期结束时会自动释放资源,因此我们不需要手动调用 delete

如果取消注释 delete ptr.get(); 这一行,会导致未定义行为,因为在 ptr 的析构函数被调用后,资源会被第二次释放,从而产生问题。

std::unique_ptr 是为了自动管理资源的所有权和释放而设计的,不要手动干预资源的释放过程。

unique_ptr避免裸指针和 release 的滥用

使用 std::unique_ptr 的一个主要目的是避免使用裸指针(原始指针)和不当使用 release 函数。裸指针的滥用可能导致资源泄漏或资源多次释放,而不当使用 release 可能导致资源泄漏或未定义行为。

以下是一个示例,展示了在使用 std::unique_ptr 时避免裸指针和不当使用 release 的重要性:

#include 
#include 

class Resource {
public:
    Resource() {
        std::cout << "Resource acquired." << std::endl;
    }

    ~Resource() {
        std::cout << "Resource released." << std::endl;
    }
};

int main() {
    // 创建一个 unique_ptr 来管理资源
    std::unique_ptr ptr = std::make_unique();

    // 错误示例:避免使用裸指针
    Resource* rawPtr = ptr.get();  // 获取裸指针,但不应该用于资源管理
    // 不要使用 rawPtr 进行资源管理
    // delete rawPtr;  // 这将导致资源多次释放

    // 错误示例:不当使用 release
    Resource* releasedPtr = ptr.release();  // 释放资源,但不应该用于裸指针
    // 这将导致资源泄漏,因为 releasedPtr 不会自动释放资源

    // 正确示例:使用 std::unique_ptr 来管理资源
    // 当 ptr 超出作用域时,资源会自动被释放
    return 0;
}

在这个示例中,我们创建了一个 std::unique_ptr 来管理 Resource 类的资源。错误示例部分演示了避免使用裸指针和不当使用 release 的情况。使用裸指针可能导致资源多次释放,而使用 release 后,资源将泄漏,因为它不会自动释放。

正确的做法是,让 std::unique_ptr 在其生命周期结束时自动管理资源的释放。这是智能指针的主要优势之一,能够避免手动管理资源的麻烦和风险。

unique_ptr自定义删除器

std::unique_ptr 允许你指定一个自定义的删除器(deleter),用于在资源管理对象被销毁时执行特定的释放操作。这在需要使用非标准的释放函数、自定义的资源管理行为或资源的清理操作时非常有用。删除器可以是函数、函数对象或者可以调用的对象,其目的是为了替代默认的 delete 操作。

以下是一个示例,展示了如何使用自定义删除器来管理文件资源:

#include 
#include 
#include 

struct FileDeleter {
    void operator()(FILE* file) const {
        if (file) {
            std::cout << "Closing file." << std::endl;
            fclose(file);
        }
    }
};

int main() {
    // 使用自定义删除器来管理文件资源
    std::unique_ptr filePtr(fopen("example.txt", "w"));

    if (filePtr) {
        std::cout << "Writing to file." << std::endl;
        fprintf(filePtr.get(), "Hello, custom deleter!");
    }

    // filePtr 超出作用域时,会自动调用 FileDeleter 释放文件资源

    return 0;
}

在这个示例中,我们定义了一个名为 FileDeleter 的自定义删除器,它会在资源被释放时关闭文件。然后,我们创建了一个 std::unique_ptr,其第二个模板参数是我们定义的删除器类型。当 filePtr 超出作用域时,会自动调用 FileDeleter 来关闭文件。

注意,在自定义删除器中,可以根据需要执行适当的资源释放操作,无论是文件句柄、数据库连接还是其他资源。这使得 std::unique_ptr 能够管理各种类型的资源,而不仅限于默认的 delete 操作。

总之,自定义删除器是 std::unique_ptr 强大的特性之一,它使得资源管理更加灵活和定制化。

你可能感兴趣的:(c++语言特性,学习,网络,服务器,网络协议,c++)