C++ 智能指针详解: std::unique_ptr 和 std::shared_ptr

C++11引入了智能指针,它们是管理动态分配内存的强大工具。本文将详细介绍两种最常用的智能指针: std::unique_ptrstd::shared_ptr

std::unique_ptr

概述

std::unique_ptr 是一种独占所有权的智能指针。它确保一个对象只能被一个 unique_ptr 所拥有,这意味着不能复制 unique_ptr,只能移动它。

主要特性

  1. 独占所有权: 一个 unique_ptr 不能被复制,只能被移动。
  2. 自动释放: 当 unique_ptr 离开作用域时,它所管理的对象会被自动删除。
  3. 零开销: 在大多数操作中, unique_ptr 与原始指针的性能相当。
  4. 自定义删除器: 可以指定自定义的删除方式。

示例代码

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "MyClass constructed\n"; }
    ~MyClass() { std::cout << "MyClass destructed\n"; }
    void doSomething() { std::cout << "Doing something\n"; }
};

int main() {
    // 创建unique_ptr
    std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
    
    // 使用->访问成员
    ptr1->doSomething();
    
    // 无法复制unique_ptr
    // std::unique_ptr<MyClass> ptr2 = ptr1; // 编译错误
    
    // 可以移动unique_ptr
    std::unique_ptr<MyClass> ptr2 = std::move(ptr1);
    
    // ptr1现在为空
    if (ptr1 == nullptr) {
        std::cout << "ptr1 is null\n";
    }
    
    // ptr2现在拥有对象
    ptr2->doSomething();
    
    // 离开作用域时,ptr2自动删除对象
}

std::shared_ptr

概述

std::shared_ptr 是一种共享所有权的智能指针。多个 shared_ptr 可以指向同一个对象,对象的内存会在最后一个引用被销毁时释放。

主要特性

  1. 共享所有权: 多个 shared_ptr 可以指向同一个对象。
  2. 引用计数: 内部维护一个引用计数,当计数降为0时删除对象。
  3. 线程安全: 引用计数的增减是原子操作,但对象本身的访问不是线程安全的。
  4. 可以从 this 指针创建: 可以安全地从一个对象的成员函数中创建指向 this 的 shared_ptr

示例代码

#include <iostream>
#include <memory>

class SharedClass : public std::enable_shared_from_this<SharedClass> {
public:
    SharedClass() { std::cout << "SharedClass constructed\n"; }
    ~SharedClass() { std::cout << "SharedClass destructed\n"; }
    
    std::shared_ptr<SharedClass> getShared() {
        return shared_from_this();
    }
};

int main() {
    // 创建shared_ptr
    auto ptr1 = std::make_shared<SharedClass>();
    
    {
        // 创建另一个指向同一对象的shared_ptr
        std::shared_ptr<SharedClass> ptr2 = ptr1;
        
        std::cout << "使用计数: " << ptr1.use_count() << std::endl; // 输出 2
        
        // 从对象内部获取shared_ptr
        auto ptr3 = ptr1->getShared();
        std::cout << "使用计数: " << ptr1.use_count() << std::endl; // 输出 3
        
        // ptr2和ptr3离开作用域,但对象不会被删除
    }
    
    std::cout << "使用计数: " << ptr1.use_count() << std::endl; // 输出 1
    
    // ptr1离开作用域,对象被删除
}

比较 unique_ptr 和 shared_ptr

特性 std::unique_ptr std::shared_ptr
所有权 独占 共享
复制 不允许 允许
移动 允许 允许
引用计数
性能开销 几乎为零 有一定开销
内存使用 与原始指针相同 额外内存用于控制块
线程安全 不适用 引用计数操作是安全的
循环引用 不会发生 可能发生,需要注意

最佳实践

  1. 优先使用 std::unique_ptr,除非确实需要共享所有权。
  2. 使用 std::make_uniquestd::make_shared 来创建智能指针。
  3. 避免使用裸指针,尽可能使用智能指针。
  4. 注意避免 std::shared_ptr 的循环引用问题,必要时使用 std::weak_ptr
  5. 在类的公共接口中返回 std::unique_ptr 来转移所有权。
  6. 在需要共享但不参与所有权的场景中使用 std::weak_ptr

std::unique_ptrstd::shared_ptr 是C++中管理动态内存的强大工具。正确使用这些智能指针可以大大减少内存泄漏的风险,提高代码的安全性和可维护性。理解它们的特性和适用场景对于编写高质量的C++程序至关重要。

posted @ 2024-09-27 18:10  非法关键字  阅读(192)  评论(0编辑  收藏  举报