24. 智能指针

1.智能指针简介

2.unique_ptr 独占式智能指针

3.shared_ptr 共享式智能指针

4.weak_ptr 弱引用智能指针


1.智能指针简介

智能指针在C++标准库(memory头文件), 核心目的是"自动管理动态分配的内存", 避免忘记手动调用delete, 造成的内存

泄露问题; 智能指针会在自身生命周期结束后(: 超出作用域)自动调用delete释放关联的内存

2.unique_ptr 独占式智能指针

unique_ptr是独占所有权的智能指针, "同一时间, 只能有一个unique_ptr指向该对象", 不支持拷贝, 仅支持移动(move)
#include <iostream>
#include <memory>  // 必须包含的头文件
using namespace std;

int main() {
    // 方式1:直接创建(不推荐,推荐make_unique)
    unique_ptr<int> up1(new int(10));
    cout << *up1 << endl;  // 输出:10

    // 方式2:C++14推荐的make_unique(更安全,避免异常导致内存泄漏)
    auto up2 = make_unique<string>("hello");
    cout << *up2 << endl;  // 输出:hello

    // ❌ 错误:unique_ptr不能拷贝(独占特性)
    // unique_ptr<int> up3 = up1;

    // ✅ 正确:移动语义(转移所有权)
    unique_ptr<int> up3 = move(up1);
    if (up1 == nullptr) {
        cout << "up1已失去对象所有权" << endl;  // 输出此句
    }
    cout << *up3 << endl;  // 输出:10

    // 手动释放(可选,一般不需要,超出作用域会自动释放)
    up3.reset();

    return 0;
}

当你直接写 unique_ptr<int> up1(new int(10)) 时,代码的执行分为两步:
执行 new int(10):动态分配内存,创建一个 int 对象;
调用 unique_ptr 的构造函数:接管第一步分配的内存。
问题出在:这两步之间可能抛出异常,导致第一步分配的内存 “无人接管”,最终内存泄漏
#include <iostream>
#include <memory>
using namespace std;

// 一个可能抛出异常的函数
void func(unique_ptr<int> ptr, int value) {
    // 业务逻辑
}

int get_value() {
    // 模拟抛出异常
    throw runtime_error("获取值失败");
    return 10;
}

int main() {
    try {
        // 危险写法:new 和 unique_ptr构造之间可能抛异常
        func(unique_ptr<int>(new int(10)), get_value());
    } catch (const exception& e) {
        cout << "异常:" << e.what() << endl;
    }
    return 0;
}

3.shared_ptr 共享式智能指针

shared_ptr是共享所有权的智能指针, 多个shared_ptr可以指向同一个对象, 内部通过引用计数管理内存; 每拷贝一个指针

引用计数+1; 每销毁一个指针, 计数-1; 当计数为0, 自动释放内存
#include <iostream>
#include <memory>
using namespace std;

int main() {
    // 推荐:make_shared创建(比直接new更安全)
    shared_ptr<int> sp1 = make_shared<int>(20);
    cout << "引用计数:" << sp1.use_count() << endl;  // 输出:1

    // 拷贝:引用计数+1
    shared_ptr<int> sp2 = sp1;
    cout << "引用计数:" << sp1.use_count() << endl;  // 输出:2

    // 修改对象值,所有指向该对象的shared_ptr都能看到
    *sp1 = 30;
    cout << *sp2 << endl;  // 输出:30

    // 手动重置:引用计数-1
    sp2.reset();
    cout << "引用计数:" << sp1.use_count() << endl;  // 输出:1

    // 程序结束,sp1销毁,计数变为0,内存自动释放
    return 0;
}

4.weak_ptr 弱引用智能指针

weak_ptr不用于"对象所有权", 专门配合shared_ptr使用

a.不会增加shared_ptr的引用计数

b.解决shared_ptr的循环引用问题("循环引用会导致引用计数无法归0, 内存泄漏")

c.不能直接解引用, 需通过lock方法转换为shared_ptr后才能访问对象("同时检查对象是否还存在")

shared_ptr释放内存的条件是: "引用计数减至0"(所有指向该对象的shared_ptr都被销毁/重置), 而循环引用会让这个条件

永远无法满足 —— 即使外部的shared_ptr都销毁了, 对象内部互相持有的shared_ptr仍会让各自的引用计数保持 ≥1
#include <iostream>
#include <memory>
using namespace std;

// 前置声明:两个类互相引用
class A;
class B;

class A {
public:
    // A持有B的shared_ptr
    shared_ptr<B> b_ptr;
    ~A() { cout << "A析构(内存释放)" << endl; } // 析构函数:验证是否销毁
};

class B {
public:
    // B持有A的shared_ptr(形成闭环)
    shared_ptr<A> a_ptr;
    ~B() { cout << "B析构(内存释放)" << endl; }
};

int main() {
    {
        // 外部创建两个shared_ptr,指向A和B对象
        shared_ptr<A> a = make_shared<A>();
        shared_ptr<B> b = make_shared<B>();

        // 互相持有:形成循环引用
        a->b_ptr = b;
        b->a_ptr = a;

        // 查看此时的引用计数
        cout << "A的引用计数:" << a.use_count() << endl; // 输出:2(a本身 + b->a_ptr)
        cout << "B的引用计数:" << b.use_count() << endl; // 输出:2(b本身 + a->b_ptr)
    } // 作用域结束:外部的a、b被销毁,引用计数各减1

    // 此时A和B的引用计数都变为1(内部互相持有),析构函数不会执行!
    cout << "作用域结束,检查是否析构" << endl;
    return 0;
}

#include <iostream>
#include <memory>
using namespace std;

// 前置声明
class A;
class B;

class A {
public:
    shared_ptr<B> b_ptr;  // 指向B的共享指针
    ~A() { cout << "A被销毁(内存释放)" << endl; }
};

class B {
public:
    weak_ptr<A> a_ptr;    // 用weak_ptr避免循环引用,而非shared_ptr
    ~B() { cout << "B被销毁(内存释放)" << endl; }
};

int main() {
    shared_ptr<A> a = make_shared<A>();
    shared_ptr<B> b = make_shared<B>();

    // 形成引用关系
    a->b_ptr = b;
    b->a_ptr = a;

    cout << "a的引用计数:" << a.use_count() << endl;  // 输出:1(weak_ptr不增加计数)
    cout << "b的引用计数:" << b.use_count() << endl;  // 输出:2(a的b_ptr是shared_ptr,计数+1)

    // 访问weak_ptr指向的对象(先lock()检查有效性)
    if (shared_ptr<A> temp = b->a_ptr.lock()) {
        cout << "成功访问A对象" << endl;
    } else {
        cout << "A对象已销毁" << endl;
    }

    return 0;
}
// 输出:
// a的引用计数:1
// b的引用计数:2
// 成功访问A对象
// B被销毁(内存释放)
// A被销毁(内存释放)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值