深入剖析C++的 “属性“(Attribute specifier sequence)

引言

在阅读开源项目源代码是,发现了一个有趣且特殊的C++特性:属性。

属性(attribute specifier sequences)是在C++11标准引入的。在C++11之前,编译器特有的扩展被广泛用来提供额外的代码信息。例如,GNU编译器(GCC)使用__attribute__来控制函数的行为。但是缺点也很明显,那就是这种方式缺乏标准化,不同编译器的特性并不兼容,严重影响了代码的可移植性。

为了解决这一问题,C++11标准引入了属性,提供一种标准化的方法来给编译器额外的信息。属性既可以应用于类型声明,也可以应用于声明语句、定义、代码块等,为编译器提供了关于编码意图的附加信息。

属性的作用

属性引入C++后,提供了以下几个方面的价值:

  1. 可移植性:提供了一种标准的方式来传达编译器特定的信息,减少了依赖特定编译器扩展的需要。

  2. 可读性:通过标准的属性,代码的特定行为和意图被清晰地表达,易于他人理解。

  3. 健壮性:属性可以帮助检测潜在的错误,如忽略了重要的函数返回值。

  4. 性能:许多属性可以帮助编译器进行优化,提高程序性能。

常见属性

以下是C++中一些常用的属性:

  1. [[noreturn]] - 表明函数不会返回到调用者。这通常用于那些通过抛出异常或终止程序来退出的函数。

  2. [[nodiscard]] - 用于函数或类型,标明调用者不应忽略返回值。对于类型,它表示该类型的对象或其构造函数返回的对象不应被忽略。

  3. [[deprecated]] - 标记某个实体(如函数、类、类型别名、变量等)为过时的,建议不要使用。可选地,可以提供一条消息说明替代的使用方式。

  4. [[fallthrough]] - 在C++17中引入,用于switch语句的case节中,明确表示允许控制流从当前case分支无条件跳转到下一个case分支的行为,避免编译器生成可能的警告。

  5. [[maybe_unused]] - 表示某个实体(如函数、类、变量等)可能不会被使用,从而防止编译器发出未使用警告。

  6. [[likely]][[unlikely]] - 这两个属性是在C++20中引入的,用来显式地指示给定的布尔表达式结果的可能性。[[likely]]表示表达式结果为true的可能性更高,而[[unlikely]]表示结果为false的可能性更高。

  7. [[no_unique_address]] - 在C++20中引入,它指示类成员不必拥有唯一的地址,允许空基优化或类似的优化技术。

这些属性可以用来改善代码的文档化、提高性能、帮助编译器检查错误和警告,以及启用或禁用特定的编译器行为。
它们是现代C++编程中代码质量和维护方面的重要工具。不同的编译器可能对属性的支持程度有所不同。

常用属性示例

[[noreturn]]

[[noreturn]]属性指示某个函数不会返回到调用者。这通常用于那些通过抛出异常或终止程序来退出的函数。

[[noreturn]] void terminate_program() {// ... 清理操作 ...std::exit(1); // std::exit不返回
}

[[nodiscard]]

[[nodiscard]]属性用于函数或类型,标明调用者不应忽略返回值。这有助于防止编码中的错误,例如忘记处理函数返回的错误代码。

[[nodiscard]] int compute() {// ... 计算操作 ...return result;
}void example() {compute(); // 如果忽略了结果,编译器可能会警告
}

C++20对nodiscard进行了扩展,支持注明原因。格式为:[[nodiscard(“reason”)]]

[[deprecated]]

[[deprecated]]属性用于标记过时的实体。

[[deprecated("Use new_function instead")]]
void old_function() {// ...
}void example() {old_function(); // 使用这个函数时,编译器会给出警告
}

[[fallthrough]]

[[fallthrough]]属性用在switch语句中,表示有意识的case穿透。

void example(int val) {switch (val) {case 1:// 计算某些事情[[fallthrough]]; // 明确表明穿透是有意为之case 2:// 1和2执行相同的代码break;default:// 其他值处理break;}
}

[[maybe_unused]]

[[maybe_unused]]属性用于可能不使用的变量或函数,防止编译器发出未使用警告。

[[maybe_unused]] static bool is_debug = true;void example() {[[maybe_unused]] int local_variable = compute();
}

[[likely]] 和 [[unlikely]]

[[likely]][[unlikely]]在C++20中引入,帮助编译器优化分支预测。

bool condition = /* ... */;
if ([[likely]] condition) {// 大多数情况下,条件为真时的代码
} else {// 条件为假时的代码
}

其他不常用的属性介绍

[[carries_dependency]] (C++11)

[[carries_dependency]]属性用来指示在函数参数或返回值中的依赖关系链可以传递,这在使用std::memory_order时或在多线程编程中非常重要。

#include <atomic>
#include <iostream>std::atomic<int> global_data;// 该函数表明参数和返回值带有依赖关系链
[[carries_dependency]] int load_data(std::atomic<int>& data) {return data.load(std::memory_order_consume);
}void process_data() {// 从全局数据载入的依赖关系被保留int local_data = load_data(global_data);// 接下来的操作可以依赖于这个顺序
}

[[no_unique_address]] (C++20)

[[no_unique_address]]属性表示非静态数据成员不必具有唯一的地址,这允许编译器在可能的情况下进行内存优化。在C++中,即使是完全空的类(不含任何成员变量或成员函数)也至少会占用1字节的大小,这是为了确保每个对象都有一个唯一的地址。但是,有时候这个额外的1字节并不是必须的,例如当空类作为其他类的成员时,这在包含多个空类成员的大型结构体中可以节省大量内存。

struct Empty {}; // empty classstruct X
{int i;Empty e;
};struct Y
{int i;[[no_unique_address]] Empty e;
};int main()
{// the size of any object of empty class type is at least 1static_assert(sizeof(Empty) >= 1); // at least one more byte is needed to give e a unique addressstatic_assert(sizeof(X) >= sizeof(int) + 1); static_assert(sizeof(Y) == sizeof(int)); 
}

[[assume(expression)]] (C++23)

[[assume(expression)]]属性告诉编译器,在给定的点上,表达式总是评估为真。这有助于编译器进行优化。

void process_data(int* ptr) {// 告诉编译器ptr不为nullptr,这有助于优化[[assume(ptr != nullptr)]]*ptr = 42;
}

[[indeterminate]] (C++26)

[[indeterminate]]属性是一个假设的属性,用来指明一个对象如果没有被初始化,则具有不确定的值。由于C++26还目前还未发布,暂时用不了。

void f(int); 
void g()
{int x [[indeterminate]]; // indeterminate valueint y;                   // erroneous valuef(x); // 允许编译通过,但是具有不确定的行为f(y); // 编译报错,不允许使用未初始化的值
}

[[optimize_for_synchronized]] (TM TS)

[[optimize_for_synchronized]]属性来自事务性内存技术规范(TM TS),它建议函数应该为同步块中的调用进行优化。TM TS不是ISO C++标准的一部分,支持度因编译器而异。

// 这个属性建议函数在同步块中调用时应该进行优化
[[optimize_for_synchronized]] void synchronized_function() {// 在同步语句中频繁调用的函数
}

结语

笔者最喜欢的C++属性就是[[nodiscard]]了,计划今天就在团队中推广开。因为许多开发者在调用一些可能失败的函数不检查返回值,导致代码鲁棒性较低。给一些重要函数加上[[nodiscard]]属性之后,编译器就能避免这种情况的发生,真是太有用了。试了一下,MSVC下nodiscard会出现警告,还好我们开了警告视为错误,那么就可以确保开发者不会忘记处理返回值了。
在这里插入图片描述

如果向了解更多关于C++属性的知识,那么可以来cppreference看看。cppreference的C++的属性参考:Attribute specifier sequence(since C++11)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/374694.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

水库大坝安全监测险情应对措施

汛期暴雨洪涝灾害发生后&#xff0c;为保证大坝及下游人民生命财产安全&#xff0c;应及时进行大坝安全现场检查和快速评估。评估内容包括大坝沉降和水平变形、裂缝、坝坡是否塌滑、下游坡是否存在集中渗漏或大面积渗水、溢洪道启闭设备能否正常运行、近坝库岸是否有大的滑坡体…

【python】PyQt5对象类型的判定,对象删除操作详细解读

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

汽车预约维修小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;技师管理&#xff0c;技师信息管理&#xff0c;用户预约管理&#xff0c;取消预约管理&#xff0c;订单信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;技师信息&a…

Ajax从零到实战

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

Unity实现安卓App预览图片、Pdf文件和视频的一种解决方案

一、问题背景 最近在开发app项目&#xff0c;其中有个需求就是需要在app软件内显示图片、pdf和视频&#xff0c;一开始想的解决方案是分开实现&#xff0c;也就是用Image组件显示图片&#xff0c;找一个加载pdf的插件和播放视频的插件&#xff0c;转念一想觉得太麻烦了&#x…

Lumos学习王佩丰Excel第四讲:排序与选择

一、排序 1、简单排序&#xff1a;不要选中一列排序&#xff0c;不然只是局部排序&#xff0c;其他数据都会发生错乱。 2、多条件排序 3、2003版本中超过3个排序条件时如何处理&#xff1a;从最后一个条件到第一个条件倒着按照要求依次排序。 4、按颜色排序 5、自定义排序次序…

LabVIEW在半导体自动化测试中的应用

半导体制造的复杂性和精密度要求极高&#xff0c;每一个生产步骤都需要严格的控制和监测。自动化测试设备在半导体制造中起到了关键作用&#xff0c;通过精密测量和数据分析&#xff0c;确保产品质量和生产效率。本文介绍如何使用LabVIEW结合研华硬件&#xff0c;开发一个用于半…

腾讯广告优量汇Android一面凉经(2024)

腾讯广告优量汇Android一面凉经(2024) 笔者作为一名双非二本毕业7年老Android, 最近面试了不少公司, 目前已告一段落, 整理一下各家的面试问题, 打算陆续发布出来, 供有缘人参考。今天给大家带来的是《腾讯广告优量汇Android一面凉经(2024)》。 面试职位: 腾讯广告优量汇-SDK客…

ensp防火墙实验

实验拓扑图 实验要求 1&#xff0c;DMZ区内的服务器&#xff0c;办公区仅能在办公时间内(9:00-18:00)可以访问&#xff0c;生产区的设备全天可以访问。 2&#xff0c;生产区不允许访问互联网&#xff0c;办公区和游客区允许访问互联网 3&#xff0c;办公区设备10.0.2.10不允…

渲染100农场是什么?渲染100邀请码1a12

作为设计师&#xff0c;渲染农场肯定听过&#xff0c;它在视觉行业有着重要作用&#xff0c;那么渲染农场是什么您知道吗&#xff1f;今天我们就来看看吧。 渲染农场&#xff0c;英文名Render Farm&#xff0c;是一种分布式并行计算系统&#xff0c;是利用现成的以太网、CPU和…

bash: redi-cli: 未找到命令...

问题描述 在执行命令&#xff1a;redi-cli --bigkeys 提示&#xff1a;bash: redi-cli: 未找到命令... 确定服务器是否有Redis进程 ps -ef | grep redis查找Redis 文件信息 find / -name "redis-*"进入到当前目录 cd /usr/bin/再次执行命令 涉及redis-cli 连…

《金山 WPS AI 2.0:重塑办公未来的智能引擎》

AITOP100平台获悉&#xff0c;在 2024 世界人工智能大会这一科技盛宴上&#xff0c;金山办公以其前瞻性的视野和创新的技术&#xff0c;正式发布了 WPS AI 2.0&#xff0c;犹如一颗璀璨的星辰&#xff0c;照亮了智能办公的新征程&#xff0c;同时首次公开的金山政务办公模型 1.…

【深度好文】合作伙伴关系管理自动化:双向共赢新趋势

在当今快速变化的商业环境中&#xff0c;合作伙伴关系已成为企业成功的关键因素之一。为了更高效地管理这些关系&#xff0c;合作伙伴关系管理自动化正逐渐成为行业的新趋势&#xff0c;它不仅简化了管理流程&#xff0c;更促进了双方共赢的局面。 一、传统管理 VS 自动化管理 …

【RHCE】实验(HTTP,DNS,SELinux,firewalld的运用)

一、题目 二、主服务器配置 1.下载HTTP服务&#xff0c;DNS服务 [rootlocalhost ~]# yum install -y httpd bind 2.开启防火墙&#xff0c;放行服务 # 开启防火墙 [rootlocalhost ~]# systemctl start firewalld # 放行服务 [rootlocalhost ~]# firewall-cmd --add-service…

【计算机毕业设计】012基于微信小程序的科创微应用平台

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

C语言-顺序表

&#x1f3af;引言 欢迎来到HanLop博客的C语言数据结构初阶系列。在这个系列中&#xff0c;我们将深入探讨各种基本的数据结构和算法&#xff0c;帮助您打下坚实的编程基础。本次我将为你讲解。顺序表&#xff08;也称为数组&#xff09;是一种线性表&#xff0c;因其简单易用…

Windows环境+C#实现显示接口测试

代码如下&#xff1a; using Models; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; …

C++入门到进阶(图文详解,持续更新中)

C入门到进阶&#xff08;图文详解&#xff0c;持续更新中&#xff09; 目录 C入门到进阶&#xff08;图文详解&#xff0c;持续更新中&#xff09; 数据 数据类型 基本数据类型/内置数据类型 C常用运算符 赋值运算符 关系运算符 逻辑运算符 杂项运算符 数据的本地化…

NFS服务器、autofs自动挂载综合实验

综合实验 现有主机 node01 和 node02&#xff0c;完成如下需求&#xff1a; 1、在 node01 主机上提供 DNS 和 WEB 服务 2、dns 服务提供本实验所有主机名解析 3、web服务提供 www.rhce.com 虚拟主机 4、该虚拟主机的documentroot目录在 /nfs/rhce 目录 5、该目录由 node02 主机…

jmeter-beanshell学习7-props获取全局变量和设置全局变量

继续写点不痛不痒的小东西。第一篇写了vars设置变量&#xff0c;但是vars只能作用在同一个线程组。跨线程组情况比较少&#xff0c;要是用到跨线程组&#xff0c;有个pros&#xff0c;用法和vars一样。 在setup线程组设置变量a&#xff0c;执行的时候&#xff0c;jmeter会先执行…