【C++】std::shared_ptr

std::shared_ptr学习笔记

基本概念

std::shared_ptr是C++标准库提供的一种智能指针,用于共享式拥有资源。它可以共享资源的所有权,确保资源在最后一个引用被销毁时自动释放。std::shared_ptr采用引用计数的方式管理资源,每个std::shared_ptr对象都会维护一个引用计数,记录有多少个对象共享了相同的资源。

内部原理

std::shared_ptr的内部原理基于引用计数。当一个std::shared_ptr对象拥有某个资源时,会在堆上分配一个控制块(control block),其中包含一个指向共享资源的指针以及一个引用计数。当有新的std::shared_ptr对象拥有相同的资源时,它们会共享同一个控制块,并且增加引用计数。当一个std::shared_ptr对象销毁时,会减少引用计数,当引用计数为0时,表示没有对象再共享资源,资源会被释放。

应用场景

  • 共享资源管理std::shared_ptr适用于需要多个对象共享同一个资源的情况,如多个对象共享一个大型数据结构或文件。
  • 循环引用处理:在一些情况下,对象之间存在循环引用,导致无法释放资源。使用std::shared_ptr可以解决这个问题,通过使用std::weak_ptr来打破循环引用。
  • STL容器元素管理std::shared_ptr可以作为STL容器(如std::vectorstd::list等)的元素类型,方便管理容器中的对象生命周期。

示例代码

#include <memory>
#include <iostream>

int main() {
    // 创建一个std::shared_ptr对象
    std::shared_ptr<int> ptr1(new int(42));

    // 创建另一个std::shared_ptr对象,共享相同的资源
    std::shared_ptr<int> ptr2 = ptr1;

    // 输出共享资源的值
    std::cout << *ptr1 << std::endl; // 输出 42
    std::cout << *ptr2 << std::endl; // 输出 42

    return 0;
}

使用技巧

  • 避免循环引用:循环引用会导致资源无法释放,可以使用std::weak_ptr来打破循环引用。
  • 优先使用std::make_shared:使用std::make_shared函数可以减少动态内存分配的开销,提高性能(见附一)。
  • 注意线程安全std::shared_ptr的引用计数是线程安全的,但多线程修改同一份资源可能会导致竞态条件,需要额外的同步措施来保证线程安全。

示例代码

#include <memory>
#include <thread>
#include <iostream>

void foo(std::shared_ptr<int> ptr) {
    // 在多线程环境中使用shared_ptr需要注意线程安全
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Value: " << *ptr << std::endl;
}

int main() {
    std::shared_ptr<int> ptr = std::make_shared<int>(42);
    std::thread t1(foo, ptr);
    std::thread t2(foo, ptr);

    t1.join();
    t2.join();

    return 0;
}

实战案例

管理动态分配的资源

#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> ptr1(new int(42));
    std::shared_ptr<int> ptr2 = ptr1;

    std::cout << *ptr1 << std::endl; // 输出 42
    std::cout << *ptr2 << std::endl; // 输出 42

    return 0;
}

STL容器中的应用

#include <memory>
#include <vector>
#include <iostream>

int main() {
    std::vector<std::shared_ptr<int>> vec;

    for (int i = 0; i < 5; ++i) {
        vec.push_back(std::make_shared<int>(i));
    }

    for (const auto& ptr : vec) {
        std::cout << *ptr << " ";
    }
    std::cout << std::endl;

    return 0;
}

​ 这些示例展示了std::shared_ptr的基本用法、内部原理、常见应用场景和使用技巧,以及实战案例。

附一

使用std::make_shared函数可以减少动态内存分配的开销主要有两个原因:

  1. 减少内存分配次数std::make_shared会在单次内存分配中同时分配控制块(用于存储引用计数和指向资源的指针)和对象所需的内存空间。而直接使用new创建std::shared_ptr时,会先分配控制块,然后再分配对象的内存空间。使用std::make_shared可以将这两步合并为一步,减少了内存分配的次数。
  2. 减少控制块的内存开销std::make_shared会为新对象分配一个更大的内存块,该内存块中包含对象的内存空间和控制块,而不是单独分配控制块和对象的内存空间。这种方法可以减少控制块的内存开销,因为多个std::shared_ptr对象可以共享同一个控制块,这样一来,只有一个控制块需要内存对齐和额外的管理信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值