C++ shared_ptr函数传值对运行效率和内容的影响

本文探讨了std::shared_ptr在函数调用中的内存拷贝问题,对比了普通const引用和const shared_ptr,并提供了优化建议。通过实例展示了shared_ptr在传值时的性能损耗,以及如何避免不必要的复制以提高效率。

贡献指针shared_ptr是一种智能化指针。
其在传入函数中时如果使用shared_ptr类型,会导致进行内存拷贝,在多次运行时将大量延长传值时间。例程如下:
引用头文件

#include <stdio.h>
#include <iostream>
#include <memory>
#include "self_timer.h"

测试函数分别传入三种不同类型的共享指针和const &(不需要拷贝内存的)

void ShardPtrFunction(std::shared_ptr<std::string> first,
                      std::shared_ptr<std::string> second) {
  // nothing to do
}

void ConstFunction(const std::string& first, const std::string& second) {
  // nothing to do
}
void ConstShardPtrFunction(const std::shared_ptr<std::string>& first,
                           const std::shared_ptr<std::string>& second) {
  // nothing to do
}

测试主程序,分别对三种方式的耗时进行统计。


int main(int argc, char* argv[]) {
  int i = 0;
  const int max_iters = 10000000;
  std::shared_ptr<std::string> first = std::make_shared<std::string>(
                                   "fhjkdsgfueawifbgjhzshjfzhjdgtusvbhjzgfjkzgj"
                                   "hbzdszfzsdgdzsgsrjgbzjsh"),
                               second = std::make_shared<std::string>(
                                   "fhjkdsgfueawifbgjhzshjfzhjdgtusvbhjzgfjkzgj"
                                   "hbzdszfzsdgdzsgsrjgbzjsh");
  {
    long start_time = GetCurrentTimeInMilliSec();
    while (i < max_iters) {
      ShardPtrFunction(first, second);
      ++i;
    }
    long end_ptr_time = GetCurrentTimeInMilliSec();
    std::cout << "time in shard_ptr: " << end_ptr_time - start_time
              << std::endl;
  }
  {
    long start_time = GetCurrentTimeInMilliSec();
    i = 0;
    while (i < max_iters) {
      ConstFunction(*first, *second);
      ++i;
    }
    long end_time = GetCurrentTimeInMilliSec();
    std::cout << "time in const&: " << end_time - start_time << std::endl;
  }

  {
    long start_time = GetCurrentTimeInMilliSec();
    i = 0;
    while (i < max_iters) {
      ConstShardPtrFunction(first, second);
      ++i;
    }
    long end_time = GetCurrentTimeInMilliSec();
    std::cout << "time in const shard_ptr&: " << end_time - start_time << std::endl;
  }

  return 1;
}

运行结果:

time in shard_ptr: 647
time in const&: 40
time in const shard_ptr&: 15
  1. 说明共享指针虽然是一个指针,但是其在传入的时会进行数值拷贝的,和值传递类似,但是又不完全相同。
  1. 其直接传入时,在函数内部重新make_shared时不改变原有数值,但是当进行指针操作时会改变原有数值。如:
void ShardPtrFunction( std::shared_ptr<std::string> first,
                       std::shared_ptr<std::string> second) {
  // first被改变为qq,且被传回
  first->assign("qq");
}
void ShardPtrFunction(std::shared_ptr<std::string> first,
                      std::shared_ptr<std::string> second) {
  // first只是在函数内部被改变为qq,不会被传回
  first = std::make_shared<std::string>("qq");
}
<think>我们被要求回答关于C++shared_ptrweak_ptr的介绍及使用。根据提供的引用内容,我们可以整理如下: 1. shared_ptr共享所有权的智能指针,使用引用计数来管理资源。 2. weak_ptr是为了配合shared_ptr而引入的,它不控制对象的生命周期,而是观测shared_ptr管理的资源。 3. weak_ptr可以解决shared_ptr循环引用导致的内存泄漏问题。 4. weak_ptr没有重载*->操作符,因此不能直接访问资源,需要通过lock()函数获得一个shared_ptr才能访问资源。 5. 在线程环境下,shared_ptr的引用计数操作是原子的,但对象的读写不是原子的。weak_ptr的lock()操作是线程安全的。 我们将按照以下结构组织回答: - 介绍shared_ptr的基本概念使用 - 介绍weak_ptr的基本概念使用 - 解释循环引用问题及weak_ptr如何解决 - 线程安全注意事项 - 代码示例说明 注意:引用内容中提供了一些代码示例,我们将适当引用并解释。 另外,根据系统级指令,数学公式代码块需要正确格式化,最后生成相关问题。 </think> ### C++智能指针shared_ptr weak_ptr 详解 #### 一、shared_ptr共享指针) `shared_ptr` 是**共享所有权**的智能指针,通过引用计数管理资源生命周期: - 当最后一个 `shared_ptr` 离开作用域时,资源自动释放 - 支持拷贝构造操作,引用计数原子性递增/递减 - 基本操作: ```cpp shared_ptr<T> sp(new T()); // 创建 sp.use_count(); // 获取引用计数 sp.reset(); // 重置指针 T* p = sp.get(); // 获取原始指针(慎用) ``` #### 二、weak_ptr(弱指针) `weak_ptr` 是 `shared_ptr` 的**观察者**,不增加引用计数: - 不拥有资源所有权,仅观测资源是否存在 - 解决 `shared_ptr` 循环引用导致的内存泄漏 - 核心操作: ```cpp weak_ptr<T> wp(sp); // 从 shared_ptr 构造 wp.expired(); // 检测资源是否已释放(use_count==0) shared_ptr<T> sp2 = wp.lock(); // 转为 shared_ptr(若资源存在) ``` #### 三、循环引用问题与解决方案 **问题场景**:相互持有的 `shared_ptr` 导致对象无法释放 ```cpp class Node { public: shared_ptr<Node> parent; // 循环引用! shared_ptr<Node> child; // 循环引用! }; ``` **解决方案**:将其中一个指针改为 `weak_ptr` ```cpp class Node { public: shared_ptr<Node> child; weak_ptr<Node> parent; // 打破循环引用 }; ``` 当父节点析构时,子节点的 `shared_ptr` 引用计数归零,触发释放[^1]。 #### 四、线程安全注意事项 1. `shared_ptr` 引用计数操作是原子的,但**对象访问非线程安全** 2. `weak_ptr::lock()` 是线程安全的,可用于安全提升指针: ```cpp void thread_func(weak_ptr<Foo> wp) { if (auto sp = wp.lock()) { // 安全提升 sp->safe_call(); // 操作共享资源 } } ``` 需配合互斥锁保证对象操作的原子性[^3]。 #### 五、关键特性对比 | 特性 | `shared_ptr` | `weak_ptr` | |---------------------|-----------------------|-----------------------| | 资源所有权 | ✅ | ❌ | | 影响引用计数 | ✅ | ❌ | | 直接访问资源 | ✅(通过 `operator->`)| ❌(需 `lock()` 转换) | | 解决循环引用 | ❌ | ✅ | | 线程安全(计数) | ✅ | ✅ | #### 六、使用示例 ```cpp #include <memory> using namespace std; struct Resource { int data = 42; }; int main() { // 创建共享资源 shared_ptr<Resource> sp(new Resource()); // 创建弱引用 weak_ptr<Resource> wp(sp); // 安全访问资源 if (auto p = wp.lock()) { cout << p->data << endl; // 输出: 42 } // 释放共享所有权 sp.reset(); // 检测资源状态 cout << wp.expired() << endl; // 输出: 1 (true) } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值