关于 unique_ptr 性能

2023-11-30

我经常读到,在大多数情况下,unique_ptr 会比 share_ptr 更受青睐,因为 unique_ptr 是不可复制的,并且具有移动语义;由于复制和引用计数,shared_ptr 会增加开销;

但是当我在某些情况下测试 unique_ptr 时,它似乎比其对应项明显慢(访问)

例如,在gcc 4.5 :

edit: print 方法实际上并不打印任何内容

#include <iostream>
#include <string>
#include <memory>
#include <chrono>
#include <vector>

class Print{

public:
void print(){}

};

void test()
{
 typedef vector<shared_ptr<Print>> sh_vec;
 typedef vector<unique_ptr<Print>> u_vec;

 sh_vec shvec;
 u_vec  uvec;

 //can't use initializer_list with unique_ptr
 for (int var = 0; var < 100; ++var) {

    shared_ptr<Print> p(new Print());
    shvec.push_back(p);

    unique_ptr<Print> p1(new Print());
    uvec.push_back(move(p1));

  }

 //-------------test shared_ptr-------------------------
 auto time_sh_1 = std::chrono::system_clock::now();

 for (auto var = 0; var < 1000; ++var) 
 {
   for(auto it = shvec.begin(), end = shvec.end(); it!= end; ++it)
   {
     (*it)->print();
   }
 }

 auto time_sh_2 = std::chrono::system_clock::now();

 cout <<"test shared_ptr : "<< (time_sh_2 - time_sh_1).count() << " microseconds." << endl;

 //-------------test unique_ptr-------------------------
 auto time_u_1 = std::chrono::system_clock::now();

 for (auto var = 0; var < 1000; ++var) 
 {
   for(auto it = uvec.begin(), end = uvec.end(); it!= end; ++it)
   {
     (*it)->print();
   }
 }

 auto time_u_2 = std::chrono::system_clock::now();

 cout <<"test unique_ptr : "<< (time_u_2 - time_u_1).count() << " microseconds." << endl;

}

平均我得到 (g++ -O0) :

  • 共享指针:1480 微秒
  • unique_ptr:3350微秒

差异从何而来?可以解释吗?


更新于 2014 年 1 月 1 日

我知道这个问题已经很老了,但结果在 G++ 4.7.0 和 libstdc++ 4.7 上仍然有效。于是,我试图找出原因。

您在这里进行的基准测试是解引用性能 using -O0并且,考虑到实施情况unique_ptr and shared_ptr,你的结果实际上是正确的。

unique_ptr将指针和删除器存储在::std::tuple, while shared_ptr直接存储裸指针句柄。因此,当您取消引用指针(使用 *、-> 或 get)时,您需要额外调用::std::get<0>() in unique_ptr。相比之下,shared_ptr直接返回指针。 在 gcc-4.7 上,即使经过优化和内联,::std::get() 也比直接指针慢一点。。经过优化和内联后,gcc-4.8.1 完全省略了 ::std::get() 的开销。在我的机器上,当编译时-O3,编译器生成完全相同的汇编代码,这意味着它们是字面上地相同。

总而言之,使用当前的实现,shared_ptr创建、移动、复制和引用计数速度较慢, but 同样快 *关于解除引用*.

NOTE: print()问题中为空,编译器在优化时会忽略循环。因此,我稍微修改了代码以正确观察优化结果:

#include <iostream>
#include <string>
#include <memory>
#include <chrono>
#include <vector>

using namespace std;

class Print {
 public:
  void print() { i++; }

  int i{ 0 };
};

void test() {
  typedef vector<shared_ptr<Print>> sh_vec;
  typedef vector<unique_ptr<Print>> u_vec;

  sh_vec shvec;
  u_vec uvec;

  // can't use initializer_list with unique_ptr
  for (int var = 0; var < 100; ++var) {
    shvec.push_back(make_shared<Print>());
    uvec.emplace_back(new Print());
  }

  //-------------test shared_ptr-------------------------
  auto time_sh_1 = std::chrono::system_clock::now();

  for (auto var = 0; var < 1000; ++var) {
    for (auto it = shvec.begin(), end = shvec.end(); it != end; ++it) {
      (*it)->print();
    }
  }

  auto time_sh_2 = std::chrono::system_clock::now();

  cout << "test shared_ptr : " << (time_sh_2 - time_sh_1).count()
       << " microseconds." << endl;

  //-------------test unique_ptr-------------------------
  auto time_u_1 = std::chrono::system_clock::now();

  for (auto var = 0; var < 1000; ++var) {
    for (auto it = uvec.begin(), end = uvec.end(); it != end; ++it) {
      (*it)->print();
    }
  }

  auto time_u_2 = std::chrono::system_clock::now();

  cout << "test unique_ptr : " << (time_u_2 - time_u_1).count()
       << " microseconds." << endl;
}

int main() { test(); }

NOTE:这不是一个根本问题,可以通过在当前 libstdc++ 实现中放弃使用 ::std::tuple 来轻松解决。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于 unique_ptr 性能 的相关文章

随机推荐

  • 如何从画布中添加和删除(多个)图像?

    我是画布 HTML5 新手 我必须在画布上设计一个绘画应用程序 有一个功能 例如在画布上动态添加所选图像 通过鼠标移动 以及删除和拖动添加的图像的功能 与文本添加相同 现在我的问题是我们如何从画布中删除图像 注意 添加到画布中的图像没有固定
  • 如何在TYPO3 CMS后端重命名副标题

    如何为作者重命名 TYPO3 CMS 后端字段 即提到的 csc styled content 内容元素字段 一般来说 覆盖标签名称可以通过后端的 Page TSconfig 来完成 下面的例子修改了标签subheader field TC
  • 你调用的对象是空的

    我有一个单元格类 public class Cell public enum cellState WATER SCAN SHIPUNIT SHOT HIT public Cell currentCell cellState WATER Me
  • 静态变量的动态初始化阶段

    该标准特别指出 静态持续时间变量 命名空间范围和类静态成员 的动态初始化不必在执行 main 之前发生 命名空间范围的对象的动态初始化 8 5 9 4 12 1 12 6 1 是否在 main 的第一个语句之前完成 是由实现定义的 IS 3
  • Jenkins-pipeline 从 groovy 中的属性文件中提取并设置变量

    首先 我将管道完全编写为 groovy 以便签入 git 请不要提供任何gui必要的解决方案 我的问题陈述是 从文件中提取变量并将其设置为等于 groovy 对象 我尝试过的 def SERVICE MAJOR VERSION node r
  • JavaScript Promise 通过 setTimeout 解决

    我不明白为什么第一个 setTimeout 函数起作用 但第二个函数不起作用 当我运行第二个 setTimeout 时 第一个被注释掉 但不是 3 秒后解决 而是立即解决 我对整个 承诺 事物很陌生 我正在学习的教程经常使用带有 setTi
  • Android 应用程序的数据大小增加是 Glide 造成的吗?

    当我使用 glide 库打开并加载少量 100 张图像时 Android 应用程序的数据大小增加了 13MB 我没有管理 glide 的任何缓存属性 全部设置为默认值 glide 的磁盘缓存是否有可能导致此问题 注意 图像大小范围为 100
  • 不可重复读和幻读有什么区别?

    有什么区别不可重复读 and 幻读 我已阅读维基百科的隔离 数据库系统 文章 但我有一些疑问 在下面的示例中 将会发生什么 不可重复读 and 幻读 交易A SELECT ID USERNAME accountno amount FROM
  • 引用变量在内存中是如何表示的?

    int num 0 int ptrNum num int refNum num 内存表 1 和表 2 中引用变量的正确表示哪一个是 如果表2 那么为什么指针是对象而引用不是 如果两种表示都不正确 请提供正确的表示并解释为什么引用不是对象 内
  • 迭代枚举类实例

    有没有一种简单的方法可以迭代 Ceylon 中类的所有枚举实例 就像values 对于 Java 枚举 abstract class Suit of hearts diamonds clubs spades shared formal St
  • 如何在 C 中捕获进程输出?

    有没有用 C 语言模拟 PHP 系统的情况 man system说 那system返回命令的状态 但我需要输出 就像在 PHP 中一样 当然 我可以使用管道来实现这一点 但是有什么标准的方法吗 您可以利用popen相关函数为 command
  • 使用交叉编译器为arm编译原生GCC

    我正在寻找为 ARM 系统创建 GCC 的本机版本 但遇到了一些麻烦 构建机器是 i686 linux 我看到的每个教程都告诉我如何设置实际的交叉编译套件 我已经使用 crosstools ng 完成了 但是 我没有看到任何与编译本机 AR
  • EXTJS 5 - 仅日期选择器年和月

    我想这个问题已经被问了很多次 因为我发现了一些有关它的主题 但我仍然不知道如何通过仅显示月份和年份来呈现日期选择器 我想我可以用不同的方式来做这件事 创建我自己的 cuctom 组件 但我认为我对 Extjs 的了解还不够好 无法创建一个显
  • 是否有一行语法用于构造包含对临时对象的引用的结构?

    考虑以下无效的 Rust 代码 有一个结构体Foo包含对第二个结构的引用Bar struct Foo lt a gt bar a Bar impl lt a gt Foo lt a gt fn new bar a Bar gt Foo lt
  • PHP 使用函数返回值作为数组

    为什么这有效 cacheMatchesNotPlayed cache gt load externalData cacheMatchesNotPlayed cacheMatchesNotPlayed matchesNotPlayed 但这不
  • 帕斯卡的三角行序列

    我目前正在努力寻找帕斯卡三角形的行序列 我想输入行号并输出列表中直到该行的数字序列 例如 Pascal 4 会给出结果 1 1 1 1 2 1 1 3 3 1 我正在尝试使用我发现的算法 这是算法本身 Vc Vc 1 r c c r and
  • MySQL:选择日期范围内的所有日期并获取与日期匹配的表数据

    有一个表 其中包含这样的数据 id date 1 2016 07 11 2 2016 07 11 3 2016 07 15 4 2016 07 15 5 2016 07 15 6 2016 07 16 7 2016 07 19 8 2016
  • Android EditText setError() 无法按预期工作

    我有问题setError on EditText 当活动打开时 它会检查某些字段是否为空 如果为空 则在其上设置错误消息 但是 只有当我在字段中写入一些文本然后将其删除时 才会显示感叹号图标 如果我失去对该字段的关注 该图标将再次消失 两个
  • Hadoop Mapreduce 控制台输出说明

    我是hadoop环境的新手 我已经设置了2节点hadoop集群 然后我运行示例 MapReduce 应用程序 实际上是字数 然后我得到这样的输出 File System Counters FILE Number of bytes read
  • 关于 unique_ptr 性能

    我经常读到 在大多数情况下 unique ptr 会比 share ptr 更受青睐 因为 unique ptr 是不可复制的 并且具有移动语义 由于复制和引用计数 shared ptr 会增加开销 但是当我在某些情况下测试 unique