shared_ptr和 weak_ptr的详细介绍

关于 shared_ptrweak_ptr 的详细介绍及使用示例:


1. shared_ptr(共享所有权智能指针)

核心特性
  • 引用计数:记录当前有多少个 shared_ptr 共享同一个对象。
  • 自动释放:当引用计数归零时,自动释放对象内存。
  • 线程安全:引用计数的增减是原子操作(但对象本身的访问需自行同步)。
基本用法
#include <memory>
#include <iostream>

class MyClass {
public:
    MyClass() { std::cout << "MyClass 构造\n"; }
    ~MyClass() { std::cout << "MyClass 析构\n"; }
    void print() { std::cout << "Hello\n"; }
};

int main() {
    // 创建 shared_ptr(推荐使用 make_shared)
    std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();

    // 共享所有权(引用计数+1)
    std::shared_ptr<MyClass> ptr2 = ptr1;

    // 使用 -> 操作符访问成员
    ptr1->print(); // 输出: Hello

    // 引用计数查看(调试用)
    std::cout << "引用计数: " << ptr1.use_count() << std::endl; // 输出: 2

    // ptr1 和 ptr2 离开作用域,引用计数归零,对象自动析构
    return 0;
}
输出结果
MyClass 构造
Hello
引用计数: 2
MyClass 析构

2. weak_ptr(弱引用智能指针)

核心特性
  • 不增加引用计数:仅观察对象,不影响其生命周期。
  • 需转换为 shared_ptr:通过 lock() 获取临时 shared_ptr 来访问对象。
  • 解决循环引用:打破 shared_ptr 的循环依赖,避免内存泄漏。

3. 循环引用问题与 weak_ptr 解决方案

循环引用示例
#include <memory>
#include <iostream>
class Node {
public:
    std::shared_ptr<Node> next;
    Node() { std::cout << "Node 构造\n"; }
    ~Node() { std::cout << "Node 析构\n"; }
};

int main() {
    auto node1 = std::make_shared<Node>();
    auto node2 = std::make_shared<Node>();
    node1->next = node2; // node2 引用计数=2
    node2->next = node1; // node1 引用计数=2

    // 退出作用域后,node1/node2 引用计数=1,无法释放!
    return 0;
}
输出结果(内存泄漏)
Node 构造
Node 构造
使用 weak_ptr 解决循环引用
#include <memory>
#include <iostream>
class SafeNode {
public:
    std::weak_ptr<SafeNode> next; // 使用 weak_ptr
    SafeNode() { std::cout << "SafeNode 构造\n"; }
    ~SafeNode() { std::cout << "SafeNode 析构\n"; }
};

int main() {
    auto node1 = std::make_shared<SafeNode>();
    auto node2 = std::make_shared<SafeNode>();
    node1->next = node2;
    node2->next = node1;

    // 退出作用域后,引用计数归零,正确析构
    return 0;
}
输出结果
SafeNode 构造
SafeNode 构造
SafeNode 析构
SafeNode 析构

4. weak_ptr 的典型使用场景

(1) 访问共享对象前检查存活状态
#include <memory>
#include <iostream>

class MyClass {
public:
    MyClass() { std::cout << "MyClass 构造\n"; }
    ~MyClass() { std::cout << "MyClass 析构\n"; }
    void print() { std::cout << "Hello\n"; }
};

void checkObject(std::weak_ptr<MyClass> weak) {
    if (auto shared = weak.lock()) { // 转换为 shared_ptr
        shared->print();
    } else {
        std::cout << "对象已被释放\n";
    }
}

int main() {
    std::weak_ptr<MyClass> weak;
    {
        auto shared = std::make_shared<MyClass>();
        weak = shared;
        checkObject(weak); // 输出: Hello
    }
    checkObject(weak); // 输出: 对象已被释放
    return 0;
}

输出结果

MyClass 构造
Hello
MyClass 析构
对象已被释放
(2) 观察者模式(缓存)
class DataCache {
    std::weak_ptr<MyClass> cachedData;
public:
    void updateCache(std::shared_ptr<MyClass> data) {
        cachedData = data;
    }
    void useCache() {
        if (auto data = cachedData.lock()) {
            data->print();
        } else {
            std::cout << "缓存无效\n";
        }
    }
};

5. shared_ptrweak_ptr 操作总结

操作shared_ptrweak_ptr
所有权拥有对象所有权仅观察对象
引用计数影响增加不影响
访问对象直接通过 ->*需调用 lock() 获取 shared_ptr
检查有效性if (ptr)if (weak.expired())lock()

6. 最佳实践

  1. 优先使用 make_shared:更高效(单次内存分配对象+控制块)。
  2. 避免循环引用:成员指针优先考虑 weak_ptr
  3. 不要用 new 初始化:直接传递裸指针可能导致多次释放。
  4. 谨慎传递 shared_ptr:仅在需要共享所有权时传递,否则传递原始引用或指针。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值