C++智能指针

Posted on Sep 25, 2016
C++11 引入了智能指针,以简化内存管理并减少内存泄漏和资源管理错误 智能指针是标准库提供的类模板,用于管理动态分配的对象的生命周期 主要有三种类型的智能指针: std::unique_ptr, std::shared_ptr, std::weak_ptr

智能智能指针是什么?

  • 智能指针: 自动管理资源的生命周期,避免内存泄漏和悬空指针
  • 所有权管理: 智能指针定义了资源的所有权和生命周期
  • RAII(Resource Acquisition Is Initialization): 智能指针利用对象生命周期自动管理资源

std::unique_ptr

std::unique_ptr 是一个独占所有权的智能指针,不允许多个 unique_ptr 实例共享同一个资源

  1. 特点:

    • 独占所有权: 一个 std::unique_ptr 对象负责一个资源的生命周期
    • 不允许拷贝: std::unique_ptr 不能被复制,只能被移动
    • 自动释放: 当 unique_ptr 超出作用域时,它会自动释放所管理的资源
  2. 使用示例:

#include <memory>

void example() {
    std::unique_ptr<int> ptr1(new int(10));
    // 或使用 make_unique (C++14及以上)
    auto ptr2 = std::make_unique<int>(20);

    // 不能复制
    // std::unique_ptr<int> ptr3 = ptr1; // 错误

    // 可以移动
    std::unique_ptr<int> ptr4 = std::move(ptr1);
}

std::shared_ptr

std::shared_ptr 是一个共享所有权的智能指针 多个 shared_ptr 实例可以共享对同一个资源的所有权,资源会在最后一个 shared_ptr 被销毁时释放

  1. 特点:

    • 共享所有权: 多个 std::shared_ptr 实例可以共同管理同一个资源
    • 引用计数: 每个 shared_ptr 持有一个引用计数,当引用计数为零时,资源会被释放
    • 允许拷贝: std::shared_ptr 可以被复制
  2. 使用示例:

#include <memory>

void example() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(10);
    std::shared_ptr<int> ptr2 = ptr1; // 共享所有权

    // 资源会在最后一个 shared_ptr 被销毁时释放
}

std::weak_ptr

std::weak_ptr 是一个不改变引用计数的智能指针,用于解决 std::shared_ptr 可能导致的循环引用问题 std::weak_ptr 不会管理资源的生命周期,而是观察 std::shared_ptr 是否仍然存在

  1. 特点:

    • 不改变引用计数: 不会影响 std::shared_ptr 的引用计数
    • 用于打破循环引用: 避免 std::shared_ptr 之间的循环引用导致内存泄漏
    • 可以通过 lock() 方法获得 std::shared_ptr
  2. 使用示例:

#include <memory>
#include <iostream>

class Resource {
public:
    std::shared_ptr<Resource> other;
};

void example() {
    std::shared_ptr<Resource> ptr1 = std::make_shared<Resource>();
    std::weak_ptr<Resource> weakPtr = ptr1; // 不影响引用计数

    if (auto sharedPtr = weakPtr.lock()) {
        std::cout << "Resource is still available.\n";
    } else {
        std::cout << "Resource has been freed.\n";
    }
}

自定义删除器

智能指针支持自定义删除器,以处理资源的特殊释放需求

  • std::unique_ptr 自定义删除器:
#include <memory>
#include <iostream>

void customDeleter(int* p) {
    std::cout << "Custom deleter called for " << *p << std::endl;
    delete p;
}

void example() {
    std::unique_ptr<int, decltype(&customDeleter)> ptr(new int(10), customDeleter);
}
  • std::shared_ptr 自定义删除器:
#include <memory>
#include <iostream>

void customDeleter(int* p) {
    std::cout << "Custom deleter called for " << *p << std::endl;
    delete p;
}

void example() {
    std::shared_ptr<int> ptr(new int(10), customDeleter);
}

常见错误

  • 循环引用std::shared_ptr 之间形成循环引用会导致内存泄漏 使用 std::weak_ptr 打破循环引用
  • 空指针解引用:访问 std::unique_ptrstd::shared_ptr 的空指针会导致未定义行为