一篇搞懂C++ STL智能指针std::shared_ptr


前言

在 C++ 编程中,智能指针是一种重要的工具,用于自动管理动态分配的内存。std::shared_ptr 是 C++11 引入的智能指针之一,它允许多个 std::shared_ptr 实例共享对同一个对象的所有权。std::shared_ptr 通过引用计数机制来管理内存的生命周期,确保对象在最后一个 std::shared_ptr 被销毁时才释放。


为什么使用 std::shared_ptr

  • 共享所有权std::shared_ptr 允许多个指针共享对同一个对象的所有权,适用于需要多个实体引用同一对象的场景。
  • 自动内存管理:智能指针自动管理对象的生命周期,避免了内存泄漏的问题。
  • 引用计数:内置的引用计数机制确保对象在所有 std::shared_ptr 实例都不再使用时才被释放。

std::shared_ptrstd::unique_ptr 的区别

  • 所有权管理

    • std::unique_ptr:独占所有权,确保同一时间只有一个智能指针拥有对象的所有权,不能被复制,只能移动。
    • std::shared_ptr:允许多个智能指针共享同一个对象的所有权,通过引用计数机制来管理对象的生命周期。
  • 引用计数

    • std::unique_ptr:没有引用计数,简单高效。
    • std::shared_ptr:使用引用计数来管理对象的生命周期,较为复杂但支持共享所有权。

std::shared_ptr 的构造函数和操作函数

构造函数

  • 默认构造函数

    std::shared_ptr();
    
    std::shared_ptr<int> p;  // 创建一个空的 shared_ptr
    
  • 构造函数(原始指针)

    explicit std::shared_ptr(T* ptr);
    
    std::shared_ptr<int> p(new int(10));  // 使用原始指针构造 shared_ptr
    
  • 拷贝构造函数

    std::shared_ptr(const std::shared_ptr& other);
    
    std::shared_ptr<int> p1(new int(20));
    std::shared_ptr<int> p2(p1);  // 拷贝构造
    
  • 移动构造函数

    std::shared_ptr(std::shared_ptr&& other) noexcept;
    
    std::shared_ptr<int> p1(new int(30));
    std::shared_ptr<int> p2(std::move(p1));  // 移动构造
    

成员函数

  • reset

    void reset(T* ptr = nullptr);
    
    std::shared_ptr<int> p(new int(40));
    p.reset(new int(50));  // 释放旧对象并拥有新对象
    
  • get

    T* get() const noexcept;
    
    std::shared_ptr<int> p(new int(60));
    int* rawPtr = p.get();  // 获取原始指针
    
  • use_count

    long use_count() const noexcept;
    
    std::shared_ptr<int> p1(new int(70));
    std::shared_ptr<int> p2 = p1;
    std::cout << "Use count: " << p1.use_count() << std::endl;  // 输出引用计数
    
  • operator*

    T& operator*() const;
    
    std::shared_ptr<int> p(new int(80));
    std::cout << *p << std::endl;  // 访问管理的对象
    
  • operator->

    T* operator->() const;
    
    struct MyClass {
        void display() const { std::cout << "Hello" << std::endl; }
    };
    std::shared_ptr<MyClass> p(new MyClass());
    p->display();  // 访问对象的成员函数
    

如果有多个 std::shared_ptr 指向同一内存

std::shared_ptr 允许多个智能指针实例共享对同一个对象的所有权。引用计数会随着 std::shared_ptr 实例的创建和销毁而增加或减少。当最后一个 std::shared_ptr 实例被销毁时,管理的对象才会被释放。

std::shared_ptr<int> p1(new int(90));
std::shared_ptr<int> p2 = p1;  // 共享所有权

std::cout << "Use count: " << p1.use_count() << std::endl;  // 输出引用计数

p1.reset();  // 释放 p1 的所有权
std::cout << "Use count after reset p1: " << p2.use_count() << std::endl;  // 输出引用计数

p2.reset();  // 释放 p2 的所有权,对象将被销毁

示例代码

下面的示例展示了 std::shared_ptr 的各种构造函数和操作函数的用法:

#include <iostream>
#include <memory>

struct MyClass {
    MyClass(int v) : value(v) {}
    int value;
    void display() const { std::cout << "Value: " << value << std::endl; }
};

int main() {
    // 使用默认构造函数
    std::shared_ptr<int> p1;

    // 使用原始指针构造函数
    std::shared_ptr<int> p2(new int(10));
    std::cout << "p2: " << *p2 << std::endl;

    // 使用拷贝构造函数
    std::shared_ptr<int> p3(p2);
    std::cout << "p3: " << *p3 << std::endl;

    // 使用移动构造函数
    std::shared_ptr<int> p4(std::move(p2));
    if (!p2) {
        std::cout << "p2 is now empty" << std::endl;
    }

    // 使用 reset 函数
    p4.reset(new int(20));
    std::cout << "p4: " << *p4 << std::endl;

    // 使用 get 函数
    std::shared_ptr<MyClass> p5(new MyClass(30));
    MyClass* rawPtrClass = p5.get();
    rawPtrClass->display();

    // 使用 use_count 函数
    std::cout << "Use count of p5: " << p5.use_count() << std::endl;

    // 使用 operator* 和 operator->
    std::shared_ptr<MyClass> p6(new MyClass(40));
    std::cout << "p6 value: " << p6->value << std::endl;
    (*p6).display();

    // 演示多个 shared_ptr
    std::shared_ptr<int> p7(new int(50));
    std::shared_ptr<int> p8 = p7;  // 共享所有权
    std::cout << "Use count: " << p7.use_count() << std::endl;
    p7.reset();  // 释放 p7 的所有权
    std::cout << "Use count after reset p7: " << p8.use_count() << std::endl;
    p8.reset();  // 释放 p8 的所有权,对象将被销毁

    return 0;
}

总结

std::shared_ptr 是一个强大的智能指针,用于管理动态分配的内存,并允许多个指针共享同一对象的所有权。通过引用计数机制,std::shared_ptr 确保对象在最后一个指针被销毁时才释放,避免了内存泄漏和悬空指针的问题。了解 std::shared_ptr 的构造函数和操作函数,有助于在需要共享对象所有权的场景中更安全、有效地管理内存。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
std::shared_ptrC++标准库中的一个智能指针类,用于管理动态分配的资源。它具有引用计数机制,可以实现多个指针共享同一个对象的所有权。 在给std::shared_ptr赋值时,有三种方式可以使用: 1) 拷贝赋值:使用一个std::shared_ptr初始化另一个std::shared_ptr,这将导致引用计数加1。 2) 移动赋值:使用std::make_shared或者直接赋值一个临时创建的std::shared_ptr,这将导致原来的std::shared_ptr失去对资源的所有权,引用计数转移。 3) 使用std::move:将一个std::unique_ptr移动给std::shared_ptr,这将导致原来的std::unique_ptr失去对资源的所有权,引用计数转移。 对于std::shared_ptr的成员函数功能,具体可以参考STL的文档或笔记。 关于std::shared_ptr的初始化,当使用裸指针初始化std::shared_ptr时,如果指针为nullptr,则std::shared_ptr的_M_ptr和_M_refcount都将为nullptr;否则,将分配内存并初始化控制块。 所以,std::shared_ptr可以用于管理动态分配的资源,并且可以共享资源的所有权。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [std::shared_ptr 详解](https://blog.csdn.net/baidu_31541363/article/details/95802210)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [[STL] std::shared_ptr笔记](https://blog.csdn.net/weixin_38734472/article/details/126486549)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人才程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值