C++中的智能指针

发布于:2025-05-22 ⋅ 阅读:(22) ⋅ 点赞:(0)

以下是关于 C++ 智能指针的系统整理,包含核心概念、经典示例及优势总结。

一、智能指针的核心概念

C++ 智能指针是一种自动管理动态内存的工具,通过 RAII(资源获取即初始化)机制,在对象生命周期结束时自动释放内存,避免手动管理内存导致的内存泄漏悬垂指针问题。

二、智能指针的三种类型

C++ 标准库提供了三种智能指针(需包含头文件 <memory>):

1. unique_ptr(独占所有权指针)

核心特性

  • 独占资源所有权:同一时间仅允许一个 unique_ptr 指向该资源。
  • 不可拷贝(禁用拷贝构造函数和赋值运算符),但可通过 std::move 转移所有权。
  • 生命周期结束时(如离开作用域)自动释放资源。

经典示例

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass(int id) : id_(id) {
        std::cout << "MyClass " << id_ << " 构造" << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass " << id_ << " 析构" << std::endl;
    }
private:
    int id_;
};

int main() {
    // 创建 unique_ptr,指向 MyClass 对象(id=1)
    std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(1);

    // 转移所有权(ptr2 接管资源,ptr1 变为空)
    std::unique_ptr<MyClass> ptr2 = std::move(ptr1);

    // ptr1 已无资源,不可访问(否则崩溃)
    // if (ptr1) { ... }  // 安全检查:ptr1 为空时条件不成立

    // ptr2 离开作用域时自动释放资源
    return 0;
}

输出结果

MyClass 1 构造
MyClass 1 析构
2. shared_ptr(共享所有权指针)

核心特性

  • 共享资源所有权:多个 shared_ptr 可通过引用计数(use_count())共享同一资源。
  • 引用计数为 0 时(所有 shared_ptr 销毁或离开作用域)自动释放资源。
  • 支持拷贝和赋值(引用计数递增)。

经典示例

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass(int id) : id_(id) {
        std::cout << "MyClass " << id_ << " 构造" << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass " << id_ << " 析构" << std::endl;
    }
};

int main() {
    // 创建 shared_ptr,指向 MyClass 对象(id=2)
    std::shared_ptr<MyClass> ptrA = std::make_shared<MyClass>(2);
    std::cout << "当前引用计数:" << ptrA.use_count() << std::endl;  // 输出:1

    // 拷贝 ptrA(引用计数递增)
    std::shared_ptr<MyClass> ptrB = ptrA;
    std::cout << "当前引用计数:" << ptrA.use_count() << std::endl;  // 输出:2

    // ptrB 离开作用域(引用计数减 1)
    {
        std::shared_ptr<MyClass> ptrC = ptrA;
        std::cout << "当前引用计数:" << ptrA.use_count() << std::endl;  // 输出:3
    }  // ptrC 销毁,引用计数回到 2

    // ptrA 和 ptrB 离开作用域(引用计数减为 0,资源释放)
    return 0;
}

输出结果

MyClass 2 构造
当前引用计数:1
当前引用计数:2
当前引用计数:3
MyClass 2 析构
3. weak_ptr(弱引用指针)

核心特性

  • 配合 shared_ptr 使用,解决循环引用问题(shared_ptr 相互引用导致引用计数无法归零)。
  • 不参与引用计数(use_count() 仅反映关联的 shared_ptr 数量)。
  • 需通过 lock() 方法获取 shared_ptr 才能访问资源(若资源已释放则返回空)。

经典示例(解决循环引用)

#include <iostream>
#include <memory>

class B;  // 前置声明

class A {
public:
    std::weak_ptr<B> b_ptr;  // 用 weak_ptr 避免循环引用
    ~A() { std::cout << "A 析构" << std::endl; }
};

class B {
public:
    std::weak_ptr<A> a_ptr;  // 用 weak_ptr 避免循环引用
    ~B() { std::cout << "B 析构" << std::endl; }
};

int main() {
    auto a = std::make_shared<A>();  // a 的引用计数=1
    auto b = std::make_shared<B>();  // b 的引用计数=1

    a->b_ptr = b;  // weak_ptr 不增加 b 的引用计数(b.use_count() 仍为 1)
    b->a_ptr = a;  // weak_ptr 不增加 a 的引用计数(a.use_count() 仍为 1)

    return 0;  // a 和 b 离开作用域,引用计数归零,正常析构
}

输出结果

B 析构
A 析构

对比:若用 shared_ptr 会导致循环引用(无法析构,内存泄漏):

// 错误示例(循环引用)
class A { public: std::shared_ptr<B> b_ptr; ~A() { ... } };
class B { public: std::shared_ptr<A> a_ptr; ~B() { ... } };

// main 中创建 a 和 b 后,a->b_ptr = b(b.use_count=2),b->a_ptr = a(a.use_count=2)
// 离开作用域时,a 和 b 的引用计数减为 1(相互引用),无法归零,资源无法释放!

三、智能指针的核心优势

优势 说明
自动内存管理 生命周期结束时自动释放资源,无需手动 delete,避免内存泄漏。
异常安全 即使发生异常,智能指针仍会在作用域结束时释放资源(RAII 保证)。
避免悬垂指针 资源释放后,所有指向它的智能指针自动失效(如 unique_ptr 置空,shared_ptr 引用计数归零)。
明确所有权语义 unique_ptr 强制独占,shared_ptr 明确共享,weak_ptr 避免循环依赖,代码意图更清晰。

四、使用场景总结

  • unique_ptr:单线程中独占资源(如函数内部管理临时对象)。
  • shared_ptr:多线程或多对象共享资源(如容器中的对象、需要被多个模块访问的资源)。
  • weak_ptr:解决 shared_ptr 的循环引用(如双向链表、对象间相互引用)。

通过智能指针,C++ 开发者可以更安全、高效地管理动态内存,大幅减少手动内存管理的错误。实际编码中,优先使用 unique_ptr(轻量、无额外开销),仅在需要共享时使用 shared_ptr,并通过 weak_ptr 避免循环引用。


网站公告

今日签到

点亮在社区的每一天
去签到