智能指针是C++中的一种特殊指针类型,它用于自动管理动态分配的内存,减少内存泄漏和悬空指针等问题。智能指针通过类封装了原始指针,并在合适的时机自动释放所指向的对象,从而避免了程序员手动管理内存的复杂性。C++11 引入了三种主要的智能指针std::unique_ptr、std::shared_ptr 和 std::weak_ptr。每种智能指针有不同的特点和用途。

1、 std::unique_ptr

std::unique_ptr 表示独占所有权的智能指针。一个 unique_ptr 只能有一个所有者,不能被复制,但可以通过 std::move 转移所有权。它确保了对象在 unique_ptr 超出作用域时自动销毁。

#include <memory>
#include <iostream>

class MyClass {
public:
    void show() { std::cout << "Hello, world!" << std::endl; }
};

int main() {
    std::unique_ptr<MyClass> ptr1(new MyClass());
    ptr1->show();
    
    // std::unique_ptr不能复制
    // std::unique_ptr<MyClass> ptr2 = ptr1; // 编译错误

    // 但是可以转移所有权
    std::unique_ptr<MyClass> ptr2 = std::move(ptr1);
    ptr2->show();
    
    // ptr1 不再拥有对象,ptr2 拥有对象
}

2、std::shared_ptr

std::shared_ptr 允许多个指针共享同一个对象的所有权。当最后一个 shared_ptr 被销毁时,对象才会被释放。这是通过引用计数实现的。

#include <memory>
#include <iostream>

class MyClass {
public:
    void show() { std::cout << "Hello from shared_ptr!" << std::endl; }
};

int main() {
    std::shared_ptr<MyClass> ptr1(new MyClass());
    ptr1->show();
    
    std::shared_ptr<MyClass> ptr2 = ptr1;  // 共享所有权
    ptr2->show();
    
    // 当所有指向 MyClass 的 shared_ptr 被销毁时,对象自动释放
}

3、std::weak_ptr

std::weak_ptr 是一个不增加引用计数的智能指针,通常与 std::shared_ptr 一起使用。weak_ptr 用于解决 shared_ptr 中的循环引用问题。weak_ptr 只提供对对象的访问权限,但不管理对象的生命周期。

#include <memory>
#include <iostream>

class MyClass {
public:
    void show() { std::cout << "Hello from weak_ptr!" << std::endl; }
};

int main() {
    std::shared_ptr<MyClass> ptr1(new MyClass());
    std::weak_ptr<MyClass> weakPtr = ptr1;  // weak_ptr 不增加引用计数

    std::shared_ptr<MyClass> ptr2 = weakPtr.lock();  // 将 weak_ptr 转换为 shared_ptr
    if (ptr2) {
        ptr2->show();
    } else {
        std::cout << "对象已被销毁!" << std::endl;
    }

    // 当 ptr1 被销毁后,ptr2 会自动失效
}

4、智能指针的适用场景

使用 std::unique_ptr当想要明确地拥有一个对象的所有权,并且不希望多个指针共享这个对象时,使用 std::unique_ptr。它适用于资源独占的情况,如文件句柄、数据库连接等。

使用std::shared_ptr当多个对象需要共享对同一资源的所有权时,使用 std::shared_ptr。它适用于需要共享资源所有权的场景,如多个线程需要访问同一个共享对象。

使用std::weak_ptr当你需要避免循环引用时,使用 std::weak_ptr。例如,在父子关系中,父对象持有子对象的 shared_ptr,而子对象持有父对象的 weak_ptr,避免形成循环引用。

推荐文档