当前位置: 首页 > article >正文

C++20那些事之何时使用可能性属性?

C++20 引入了 [[likely]][[unlikely]] 这两个可能性属性,它们会给编译器优化提示,表示对应代码路径可能/不可能被执行。

乍一看,这似乎是一组很不错的属性,通过编译器优化,从而提高性能。但是事实并不是如此。

在C++ 标准草案中明确提到:Excessive usage of either of these attributes is liable to result in performance degradation.

即:过度使用任何一个属性都可能导致性能下降。

https://eel.is/c++draft/dcl.attr.likelihood#note-2

那么在什么情况下会比较有用,什么情况下又不需要呢?

本文谈谈自己的观点。

1.原则

使用时应该遵循以下原则:

  1. 谨慎使用:仅在你确定某个分支或路径在运行时极其可能或不可能时使用这些属性。

例如:下面这个判断一个value是不是大于0,如果输入的数据无法保证value很大概率/一定是大于0的,那么下面这个优化没有任何意义。

if (value > 0) [[likely]] {
    std::cout << "Value is positive: " << value << std::endl;
} else [[unlikely]] {
    std::cout << "Value is non-positive: " << value << std::endl;
}

例如:标准库中使用unlikely的示例。_Variant_storage结构体中的成员函数使用了这个属性,无效的概率非常低,所以可能使用unlikely去标记。

constexpr void
_M_reset()
{
  if (!_M_valid()) [[unlikely]]
    return;

  // do something
}
  1. 标记主导路径:只在主导执行路径上使用属性,而不是在所有可能路径上。

例如:下面一个if判断标记了两个等效的likely,那么这个意义不大。

if (value > 10) [[likely]] {
    // 主导路径:值大于 10
    std::cout << "Value is greater than 10: " << value << std::endl;
} else if (value > 5) [[likely]] {
    // 次主导路径:值大于 5 且小于等于 10
    std::cout << "Value is greater than 5 but less than or equal to 10: " << value << std::endl;
} else [[unlikely]] {
    // 较少出现的路径:值小于等于 5
    std::cout << "Value is 5 or less: " << value << std::endl;
}

2.示例

最后举一个比较常见的例子,那便是vector的at,我们知道它会判断是否超过vector的size,这种概率比较低,所以我们可以使用unlikely,例如:

int& at(std::vector<int>& vec, std::size_t i) {
  if (i >= vec.size()) [[unlikely]] {
      throw std::out_of_range("Out of bounds access");
  }
  return vec[i];
}

最后对这个做一个benchmark,得到一个对比图,可以看到使用unlikely可以提升一定的性能,但不太大,当让也与测试代码关系。

注:完整代码与测试步骤已发星球,感兴趣加入星球即可。

4d1419e5ac0ede58ea8970a9c8030baa.jpeg

一起探索更多C++项目/知识~

92c86b96a8eb918c9a689fd80076d966.jpeg

往期推荐:

向量数据库milvus源码剖析之开篇

热度更新,手把手实现工业级线程池

玩转cpp小项目星球3周年了!

95d7c4d653ac2e019af83cb2710cbba9.jpeg


http://www.kler.cn/a/302120.html

相关文章:

  • Flask和Python实现在线课堂学生疲劳检测系统设计与实现
  • 【C++】string(一)
  • Python教程笔记(3)
  • MDK 5 各个历史版本下载地址
  • Vue3 -- 项目配置之stylelint【企业级项目配置保姆级教程3】
  • 【MySQL 保姆级教学】事务的自动提交和手动提交(重点)--上(13)
  • 银行业金融机构反洗钱现场检查数据接口规范(试行)
  • 如何升级用 Helm 安装的极狐GitLab Runner?
  • C#发送正文带图片带附件的邮件
  • Eclipse折叠if、else、try catch的{}
  • Git 提取和拉取的区别在哪
  • 【Jupyter Notebook】安装与使用
  • DBeaver 连接 mysql 报错:Public Key Retrieval is not allowed
  • MySQL 数据库与表的创建指南
  • JeecgBoot自定义多选组件JCheckBtnGroup
  • 携手Vatee万腾平台,共赴智能时代新征程
  • 电气负载模拟器
  • Zookeeper工作机制、特点、数据结构、应用场景、配置参数解读
  • RTCP协议
  • 【数据结构(初阶)】——二叉树
  • 【go-zero】api与rpc使用etcd服务发现
  • 三维坐标变换
  • JAVA宠物界的Uber同城遛狗兼职系统小程序源码
  • 手机玩机常识-------谷歌系列机型解锁bl详细步骤 其他机型可以借鉴参考
  • EG边缘计算网关连接中移ONENET物联网平台(MQTT协议)
  • 【微处理器系统原理与应用设计第十二讲】通用定时器设计二之PWM波实现呼吸灯的功能