C++:使用shared_ptr智能指针构造对象方法不同导致效率问题

😝代码背景:代码中遇到了使用智能指针shared_ptr构造对象,不同的方法会有不同的效率优劣,如下

第一行代码:

std::shared_ptr<Dog> newDogName(new Dog(API::NamingDog(a,b)));

第二行代码:

std::shared_ptr<Dog> newDogName=std::make_shared<Dog>(API::NamingDog(a,b));

解析:

第二行代码的效率会更高,解释如下

第一行代码的情况,使用newshared_ptr构造函数

当你使用new操作符创建一个对象,然后将其传递给shared_ptr的构造函数时,会发生以下步骤:

  1. 内存分配:new操作符首先为对象分配内存。
  2. 对象构造:然后,对象的构造函数被调用,初始化分配的内存。
  3. 控制权转移:new返回一个原始指针,这个指针随后被传递给shared_ptr的构造函数。
  4. 引用计数初始化:shared_ptr构造函数接收原始指针,并初始化内部的引用计数(默认为1)。
  5. 删除器(可选):如果提供了删除器,shared_ptr还会存储删除器的副本。

这个过程涉及两次内存分配:一次是new操作符分配对象内存,另一次是shared_ptr构造函数分配引用计数器的内存。

第二行代码的情况,使用std::make_shared

std::make_shared是一个优化的函数,它将上述两个步骤合并为一次内存分配

  1. 一次内存分配:make_shared首先分配足够的内存来存储对象和shared_ptr的控制块(包含引用计数等信息)。这是通过一次调用内存分配函数完成的,通常是operator new。
  2. 对象构造:接着,make_shared在分配的内存中直接构造对象,无需额外的内存分配。
  3. 返回shared_ptr:最后,make_shared返回一个shared_ptr,它已经拥有对象的所有权,并且引用计数已经初始化为1。

为什么make_shared只需要一次内存分配

make_shared之所以只需要一次内存分配,是因为它使用了一种称为“控制块和数据块合并”的技术。make_shared分配的内存足够大,可以同时存储对象本身和shared_ptr所需的控制信息(如引用计数)。这样,就避免了shared_ptr构造函数需要单独分配内存来存储控制信息的需要。

这种方法的优势在于:

  • 效率:减少了内存分配的次数,提高了内存分配的效率。
  • 性能:减少了构造shared_ptr时的开销,因为不需要额外的内存分配和复制操作。
  • 安全性:make_shared是线程安全的,它内部实现了必要的同步机制,而手动构造shared_ptr可能需要额外的同步措施来保证线程安全。

因此,std::make_shared是推荐的方式,用于创建由shared_ptr管理的对象,因为它更高效、更简洁,并且在多线程环境中更安全。

什么是引用计数?

引用计数是一种用于管理动态分配内存(如C++中的堆内存)的技术,它允许多个指针或对象共享对内存的所有权。在引用计数机制中,每个动态分配的对象都有一个与之关联的计数器,这个计数器记录了当前指向该对象的指针数量。

以下是引用计数的工作原理:

  1. 初始分配:当使用new操作符创建一个对象时,通常会分配内存并初始化对象。如果使用智能指针(如std::shared_ptr),则同时会创建一个引用计数。
  2. 计数增加:每当创建一个新的指针指向该对象时,引用计数增加。对于std::shared_ptr,每次复制shared_ptr时,引用计数也会增加。
  3. 计数减少:当一个指向对象的指针被销毁或重新赋值时,引用计数减少。对于std::shared_ptr,当shared_ptr超出作用域或被销毁时,引用计数会减少。
  4. 检查计数:每当引用计数减少,系统会检查计数器的值。如果引用计数达到零,这意味着没有任何指针再指向该对象,因此对象不再被需要。
  5. 内存释放:当引用计数为零时,对象会被自动销毁,分配给对象的内存会被释放,引用计数器也会被销毁。

引用计数的优点包括:

  • 自动内存管理:自动释放不再需要的对象,减少内存泄漏的风险。
  • 共享所有权:允许多个指针共享对同一对象的所有权,简化资源管理。

然而,引用计数也有其缺点:

  • 循环引用问题:如果两个或多个对象相互引用,它们的引用计数永远不会达到零,导致内存泄漏。这通常需要额外的机制(如弱指针)来解决。
  • 性能开销:每次复制或销毁指针时,都需要更新引用计数,这可能会引入额外的性能开销。
  • 线程安全问题:在多线程环境中,修改引用计数需要同步机制,以避免竞态条件。

在C++中,std::shared_ptr使用引用计数来管理其管理的对象的生命周期。当最后一个shared_ptr被销毁时,对象会被自动删除,从而防止内存泄漏。

有错误恳请指正!!!!!!!

  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值