C++三种智能指针unique、shared、weak

unique_ptr 独占所有权 90%使用

无计数机制

std::make_unique<int>(100); 创建对象 单个变量int up1=100

std::move转移所有权,原指针变为空

unique_ptr::reset() 释放对象、原始指针

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

int main() {
    std::cout << "=== unique_ptr 演示 ===\n";
    
    // 创建时:我是唯一的主人
    std::unique_ptr<int> up1 = std::make_unique<int>(100);
    std::cout << "创建up1,值是: " << *up1 << std::endl;
    
    // 不能直接拷贝!会编译错误
    // std::unique_ptr<int> up2 = up1; // ❌ 错误!
    
    // 只能转移所有权
    std::unique_ptr<int> up2 = std::move(up1); // 所有权转移
    
    std::cout << "转移后: ";
    if (up1) {
        std::cout << "up1有值: " << *up1 << std::endl;
    } else {
        std::cout << "up1为空(所有权已转移)\n"; // 执行这里
    }
    
    if (up2) {
        std::cout << "up2有值: " << *up2 << std::endl; // 执行这里
    }
    
    return 0;
    // up2超出作用域,自动删除管理的对象
}

shared_ptr 共享所有权

创建对象时计数,拷贝赋值共享数量,

std::shared_ptr<T> ptr = std::make_shared<T>(构造参数); 创建对象

shared_ptr.use_count(); 返回当前共享对象所有权的 shared_ptr 数量 强引用计数

res2.reset(); 提前释放智能指针及资源

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

int main() {
    std::cout << "=== shared_ptr 引用计数演示 ===\n";
    
    // 步骤1:创建第一个shared_ptr
    std::shared_ptr<int> sp1 = std::make_shared<int>(42);
    std::cout << "创建sp1后,引用计数: " << sp1.use_count() << std::endl; // 输出: 1
    
    // 步骤2:通过拷贝构造创建第二个shared_ptr
    std::shared_ptr<int> sp2 = sp1; // 拷贝构造,共享所有权
    std::cout << "创建sp2(sp1的拷贝)后,引用计数: " << sp1.use_count() << std::endl; // 输出: 2
    
    // 步骤3:通过赋值创建第三个shared_ptr
    std::shared_ptr<int> sp3;
    sp3 = sp1; // 赋值操作,共享所有权
    std::cout << "sp3 = sp1后,引用计数: " << sp1.use_count() << std::endl; // 输出: 3
    
    // 步骤4:sp2被重新赋值(指向新对象)
    sp2 = std::make_shared<int>(100); // sp2不再共享,指向新对象
    std::cout << "sp2指向新对象后,sp1的引用计数: " << sp1.use_count() << std::endl; // 输出: 2
    
    // 步骤5:sp3超出作用域(在代码块内)
    {
        std::shared_ptr<int> sp4 = sp1; // 在代码块内创建
        std::cout << "在代码块内创建sp4后,引用计数: " << sp1.use_count() << std::endl; // 输出: 3
    } // sp4超出作用域,自动销毁
    
    std::cout << "sp4销毁后,引用计数: " << sp1.use_count() << std::endl; // 输出: 2
    
    return 0;
    // sp1和sp3超出作用域,引用计数从2减到0,对象被销毁
}

详细计数过程表格

步骤 操作 sp1计数 sp2计数 sp3计数 说明
1 sp1 = make_shared(42) 1 - - 创建对象,计数=1
2 sp2 = sp1 2 2 - 拷贝构造,两个指针共享,计数=2
3 sp3 = sp1 3 3 3 赋值操作,三个指针共享,计数=3
4 sp2 = make_shared(100) 2 1 2 sp2指向新对象,原对象计数减1
5 创建sp4(在代码块内) 3 1 3 又一个共享者
6 sp4销毁(代码块结束) 2 1 2 sp4超出作用域,计数减1
7 main结束,所有指针销毁 0 0 0 对象被正确删除

weak_ptr 弱引用

创建std::weak_ptr<int> wp1 = sp1 添加弱引用计数(增加) 【强引用不变】

通过 lock() 获取临时 shared_ptr 此时强引用计数增加 【弱引用不变】

退出{}代码块时临时强引用解析计数-1

sp1.reset(); 手动提前释放,不写在main结尾也会自动释放的
std::shared_ptr的控制块维护两个计数器:

强引用计数:shared_ptr的数量,决定对象何时被销毁

弱引用计数:weak_ptr的数量,决定控制块本身何时被销毁

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

int main() {
    std::cout << "=== weak_ptr 弱引用计数演示 ===\n";
    
    // 步骤1:创建shared_ptr
    std::shared_ptr<int> sp1 = std::make_shared<int>(999);
 /* 强引用计数 = 1 弱引用计数 = 0 对象状态:存活*/

    std::cout << "创建sp1后 - 强引用计数: " << sp1.use_count() << std::endl; // 输出: 1
    
    // 步骤2:创建weak_ptr(不增加强引用计数!)
    std::weak_ptr<int> wp1 = sp1;
 /*强引用计数 = 1(不变)弱引用计数 = 1(增加)对象状态:存活*/

    std::cout << "创建wp1(来自sp1)后 - 强引用计数: " << sp1.use_count(); // 输出: 1(不变!)
    // 注意:use_count()只返回强引用计数,弱引用计数是隐藏的
    
    // 步骤3:通过weak_ptr获取shared_ptr
    {
        std::shared_ptr<int> sp2 = wp1.lock(); // 如果对象还存在,获取shared_ptr
        if (sp2) {
            std::cout << ", 通过wp1.lock()成功,强引用计数: " << sp1.use_count() << std::endl; // 输出: 2
        }
    } // sp2销毁
    /*进入块时:强引用计数 = 2(sp1 + sp2)    弱引用计数 = 1 对象状态:存活*/
    /*退出块时(sp2析构):强引用计数 = 1(sp1)弱引用计数 = 1 对象状态:存活*/
    
    std::cout << "sp2销毁后 - 强引用计数: " << sp1.use_count() << std::endl; // 输出: 1
    
    // 步骤4:原始shared_ptr销毁
    sp1.reset(); // 手动销毁sp1
    std::cout << "sp1.reset()后 - sp1的use_count(): " << sp1.use_count() << std::endl; // 输出: 0
    
    // 步骤5:尝试通过已失效的weak_ptr获取对象
    std::shared_ptr<int> sp3 = wp1.lock();
    /*强引用计数 = 0 → 对象被销毁弱引用计数 = 1(wp1仍存在)对象状态:已销毁,但控制块仍在*/
    if (sp3) {
        std::cout << "成功获取对象\n";
    } else {
        std::cout << "对象已被销毁,获取失败\n"; // 执行这里
    }
    
    return 0;
}

/* 强引用计数 = 1 弱引用计数 = 0 对象状态:存活*/

std::shared_ptr<int> sp1 = std::make_shared<int>(999);
/*强引用计数 = 1(不变)弱引用计数 = 1(增加)对象状态:存活*/

std::weak_ptr<int> wp1 = sp1;
/*进入块时:强引用计数 = 2(sp1 + sp2) 弱引用计数 = 1 对象状态:存活*/

/*退出块时(sp2析构):强引用计数 = 1(sp1)弱引用计数 = 1 对象状态:存活*/

{

std::shared_ptr<int> sp2 = wp1.lock(); // 如果对象还存在,获取shared_ptr

if (sp2) {

std::cout << ", 通过wp1.lock()成功,强引用计数: " << sp1.use_count() << std::endl; // 输出: 2

}

} // sp2销毁
/*提前释放资源,冗余操作,在main结尾会自动释放*/

/*强引用计数 = 0 → 对象被销毁弱引用计数 = 1(wp1仍存在)

sp1.reset(); // 手动销毁sp1
/*强引用计数 = 0 → 对象被销毁弱引用计数 = 1(wp1仍存在)对象状态:已销毁,但控制块仍在*/

//尝试通过已失效的weak_ptr获取对象

std::shared_ptr<int> sp3 = wp1.lock();

if (sp3) {

std::cout << "成功获取对象\n";

} else {

std::cout << "对象已被销毁,获取失败\n"; // 执行这里

}

相关推荐
Bona Sun38 分钟前
单片机手搓掌上游戏机(十六)—pico运行fc模拟器之程序修改烧录
c语言·c++·单片机·游戏机
9ilk1 小时前
【C++】 --- 哈希
c++·后端·算法·哈希算法
AGANCUDA1 小时前
qt使用osg显示pcd点云的例子
开发语言·qt
小邓   ༽1 小时前
50道C++编程练习题及解答-C编程例题
c语言·汇编·c++·编程练习·c语言练习题
2301_815686451 小时前
extern
java·开发语言
报错小能手1 小时前
数据结构 定长顺序表
数据结构·c++
q***56381 小时前
Java进阶-SPI机制
java·开发语言
合作小小程序员小小店1 小时前
桌面开发,在线%物品代送,代接管理%系统,基于vs2022,c#,winform,sql server数据。
开发语言·数据库·sql·microsoft·c#
qq_419203231 小时前
深浅拷贝、STL迭代器失效
c++·深浅拷贝·stl迭代器失效