C++新特性—— 智能指针(shared_ptr/unique_ptr/weak_ptr)

C++11引入了智能指针,用于自动管理动态内存的释放,避免内存泄漏。常用的智能指针有 unique_ptrshared_ptrweak_ptr,每种类型的智能指针有不同的特点和使用场景。

头文件为<memory>

1. unique_ptr 智能指针

unique_ptr 是独占指针,即某个动态分配的内存只能被一个 unique_ptr 所拥有,不支持拷贝和赋值操作。它会在超出作用域时自动释放资源。

示例代码:

cpp 复制代码
#include <iostream>
#include <memory>

using namespace std;

int main()
{
    unique_ptr<int> p1(new int(24));
    cout << "*p1 = " << *p1 << endl << endl;

    unique_ptr<int> p2 = move(p1); // 使用 move 转移所有权
    cout << "*p2 = " << *p2 << endl << endl;

    p2.reset(); // 显式释放内存
    p1.reset(); 

    unique_ptr<int> p3(new int(250));
    p3.reset(new int(666)); // 绑定动态对象
    cout << "*p3 = " << *p3 << endl << endl;

    p3 = nullptr; // 显式销毁指向的对象,同时智能指针变为空,等价于 p3.reset()

    unique_ptr<int> p4(new int(999));
    int* p = p4.release(); // 释放控制权,内存不释放
    cout << "*p = " << *p << endl << endl;

    // p4 已经没有管理任何对象,访问会导致错误
    // cout << "*p4 = " << *p4 << endl;

    delete p; // 手动释放内存
    return 0;
}

输出结果:

bash 复制代码
*p1 = 24

*p2 = 24

*p3 = 666

*p = 999

关键点:

  • unique_ptr 不能拷贝,只能通过 std::move 转移所有权。

  • reset() 用来释放智能指针管理的内存,release() 用来转移控制权但不释放内存。


2. shared_ptr 智能指针

shared_ptr 是共享指针,多个 shared_ptr 可以指向同一块动态内存,并通过引用计数的方式管理内存的生命周期。引用计数为零时,资源会被释放。

shared_ptr 的核心是一个叫 控制块(control block) 的结构体,它记录了以下两个关键信息:

  1. 指向资源的原始指针(void *ptr

  2. 引用计数(ref_count)

可以把它想象成这样(伪结构体):

cpp 复制代码
struct ControlBlock {
    int ref_count; // 当前有多少 shared_ptr 指向这块内存
    void* ptr;     // 指向实际数据的指针
};

示例代码:

cpp 复制代码
#include <iostream>
#include <memory>
using namespace std;

int main()
{
    shared_ptr<int> p1(new int(456));
    shared_ptr<int> p2 = p1; // 共享所有权
    cout << "p2 引用计数: " << p2.use_count() << endl << endl;

    cout << "*p1 = " << *p1 << endl;
    cout << "*p2 = " << *p2 << endl;
    cout << "p2 引用计数: " << p2.use_count() << endl << endl;

    p1.reset(); // p1 不再管理内存
    cout << "p2 引用计数: " << p2.use_count() << endl << endl;

    return 0;
}

代码解释:

  • 每个 shared_ptr 都会共享同一个"引用计数控制块"。

  • 当新的 shared_ptr 被复制时,引用计数 +1;

  • 当某个 shared_ptr 调用 reset() 或超出作用域时,引用计数 -1;

  • 当引用计数减为 0 时,内存会被自动释放。

输出结果:

bash 复制代码
p2 引用计数: 2

*p1 = 456
*p2 = 456
p2 引用计数: 2

p2 引用计数: 1

关键点:

  • shared_ptr 会自动管理内存,通过引用计数来确保内存安全。

  • use_count() 用来获取当前对象的引用计数。

  • reset() 用来重置 shared_ptr,使其释放控制的内存。


3. make_shared 函数

make_shared 是创建 shared_ptr 的推荐方法,它通过单次内存分配实现了更高效的内存管理。它不仅分配内存给对象,还分配了用于引用计数的内存。

示例:

cpp 复制代码
auto p = make_shared<int>(10);

shared_ptr(new int(10)) 的区别在于:

  • make_shared 会一次性分配内存,效率更高。

例如:

(1)shared_ptr

cpp 复制代码
shared_ptr<int> p1(new int(10));

这里是创建一个 shared_ptr,同时通过 new 操作符分配了一个 int 类型的动态内存。这样,shared_ptr 管理的是一个指向动态内存的原始指针。首先,new int(10) 分配了内存给 int 类型的对象,然后 shared_ptr 会为引用计数分配内存。因此总共进行了 两次内存分配 :一次是为对象本身分配内存(即 int 类型的内存),一次是为 shared_ptr 维护的引用计数分配内存

(2)make_shared

cpp 复制代码
auto p2 = make_shared<int>(10);

使用 make_shared,它会一次性分配内存,同时为对象本身和引用计数分配内存。即,make_shared 只需要 一次内存分配,同时包含了对象和引用计数的信息。

  • 它避免了内存泄漏的风险,特别是在异常情况下。

4. weak_ptr 智能指针

weak_ptr 是辅助 shared_ptr 使用的智能指针,它不增加或减少引用计数,因此它并不拥有资源的所有权。weak_ptr 不能直接访问资源,但可以通过 lock() 方法将其转化为 shared_ptr 进行访问。

示例代码:

cpp 复制代码
#include <iostream>
#include <memory>
using namespace std;

int main()
{
    shared_ptr<int> p1(new int(300));
    shared_ptr<int> p2 = p1;
    weak_ptr<int> wp = p1; // weak_ptr 不增加引用计数

    cout << "wp 引用计数: " << wp.use_count() << endl << endl;
    cout << "*p1 = " << *p1 << endl;
    cout << "*p2 = " << *p2 << endl;
    cout << endl;

    return 0;
}

输出结果:

bash 复制代码
wp 引用计数: 2

*p1 = 300
*p2 = 300

关键点:

  • weak_ptr 不拥有资源的所有权,不能直接使用资源。

  • 使用 lock() 方法可以获得一个 shared_ptr,从而访问资源。


5.总结

  • unique_ptr:独占资源,无法拷贝或赋值,适用于资源的独占管理。

  • shared_ptr:共享资源,通过引用计数管理内存,适用于多个对象需要共享同一资源的场景。

  • weak_ptr:辅助 shared_ptr,不增加引用计数,避免循环引用,适用于观察者模式等场景。

相关推荐
W23035765735 小时前
经典算法:最长上升子序列(LIS)深度解析 C++ 实现
开发语言·c++·算法
.Ashy.5 小时前
2026.4.11 蓝桥杯软件类C/C++ G组山东省赛 小记
c语言·c++·蓝桥杯
minji...6 小时前
Linux 线程同步与互斥(三) 生产者消费者模型,基于阻塞队列的生产者消费者模型的代码实现
linux·运维·服务器·开发语言·网络·c++·算法
CoderCodingNo8 小时前
【GESP】C++三级真题 luogu-B4499, [GESP202603 三级] 二进制回文串
数据结构·c++·算法
hetao17338379 小时前
2026-04-09~12 hetao1733837 的刷题记录
c++·算法
6Hzlia9 小时前
【Hot 100 刷题计划】 LeetCode 136. 只出现一次的数字 | C++ 哈希表&异或基础解法
c++·算法·leetcode
汉克老师10 小时前
GESP2024年6月认证C++三级( 第二部分判断题(1-10))
c++·数组·位运算·补码·gesp三级·gesp3级
无限进步_11 小时前
【C++】只出现一次的数字 II:位运算的三种解法深度解析
数据结构·c++·ide·windows·git·算法·leetcode
小贾要学习11 小时前
【Linux】TCP网络通信编程
linux·服务器·网络·c++·网络协议·tcp/ip
哎嗨人生公众号12 小时前
手写求导公式,让轨迹优化性能飞升,150ms变成9ms
开发语言·c++·算法·机器人·自动驾驶