现代C++中的属性语法

无论是GCC还是MSVC都提供了属性语法,而从C++11起,stl也提供了属性语法可以适用于不同的系统环境。

 

1. GCC和MSVC的属性语法

GCC中的属性语法即__attribute__,详细的介绍参阅我以前的博客:https://www.cnblogs.com/Asp1rant/p/14921559.html

MSVC中的属性语法即__declspec(attribute),常用的用于制作dll库的语句:

__declspec(dllimport) class X {} varX;

 

2. 标准属性说明符语法

c++11 中的标准属性语法:

[[attr]] [[attr1, attr2, attr3(args)]] [[namespace::attr(args)]]

C++11标准属性可以用在C++中的几乎所有位置,不过特定的一些属性智能用在特定位置。

属性说明符总是声明位于其之前的对象,而在整个声明之前的属性则会声明语句中所有声明的对象。

[[attr1]] class [[attr2]] X {int i;} a, b [[attr3]];

上例中,attr1用于对象a和b, attr2声明了类型X, X的属性也会影响到a和b,attr3只声明了对象b。

 

3. 标准属性

C++目前为止定义了9种标准属性

1. noreturn

 

复制代码
1 [[noreturn]] void foo() {cout << "foo called" << endl;}
2 
3 void bar() {cout << "bar called" << endl;}
4 
5 int main(int argc, char *argv[])
6 {
7     foo();
8     bar();
9 }
复制代码

 

noreturn用于声明函数不回返回,与void不同的是,void实际上是返回给调用者

 

上例中,bar()并不会被调用。

 

2. carries_dependency

改属性允许跨函数传递内存依赖项,通常用于弱内存顺序架构平台上多线程程序优化,避免编译器生成不必要的内存栅栏指令。、

 

3. deperacated

带有此属性的实体被声明为启用,编译器会发出警告但是依然可以用。

 

4. fallthrough

改属性用于switch,告诉编译器直落行为是有意的,不需要给出警告。

 

复制代码
 1 #include <iostream> 
 2 using namespace std; 
 3   
 4 // Driver Code 
 5 int main() 
 6 { 
 7     int n = 1; 
 8   
 9     // Switch Cases 
10     switch (n) { 
11     case 1: { 
12         cout << "work through one \n"; 
13                 [[fallthrough]];
14     } 
15     case 2: { 
16         cout << "work through two \n"; 
17                 [[fallthrough]];
18     } 
19     case 3: { 
20         cout << "work through three \n"; 
21                 [[fallthrough]];
22     } 
23     default: { 
24         cout << "work through default \n"; 
25     } 
26     } 
27   
28     return 0; 
29 } 
复制代码

 

 

5. nodiscard

该属性声明函数的返回值不应该被舍弃,否则鼓励编译器给出警告提示

 

复制代码
 1 class [[nodiscard]] X {};
 2 
 3 [[nodiscard]] int foo() {return 1;}
 4 X bar() {return X();}
 5 
 6 int main(int argc, char *argv[])
 7 {
 8     X x;
 9     foo();
10     bar();
11     return 0;
12 }
复制代码

 

这里 foo定义了返回值但是没用,定义了X的实例也没用,会给出警告。

 

 

6. maybe_unused

用于参数,一般来说函数的参数如果没在函数中使用,会被编译器警告,加上这个就不会警告

1 int foo(int a [[maybe_unused]]) {
2     return 0;
3 }

 

7. likely & 8. unlikely

likely允许编译器对改属性所在的执行路径相对于其它执行路径进行优化,而unlikely恰恰相反。通常用于switch

 

1 int f(int i) {
2     switch(i) {
3     case 1: return 1;
4     [[unlikely]]case 2: return 2;
5     }
6     return 3;
7 }

 

 

9. no_unique_address

改属性指示编译器该数据成员不需要唯一的地址,也就是说它不需要与其它非静态数据成员使用不同的地址。

 

复制代码
 1 #include <iostream>
 2 
 3 struct Empty {}; // 空类
 4 
 5 struct X {
 6     int i;
 7     Empty e;
 8 };
 9 
10 struct Y {
11     int i;
12     [[no_unique_address]] Empty e;
13 };
14 
15 struct Z {
16     char c;
17     [[no_unique_address]] Empty e1, e2;
18 };
19 
20 struct W {
21     char c[2];
22     [[no_unique_address]] Empty e1, e2;
23 };
24 
25 int main()
26 {
27     // 任何空类类型对象的大小至少为 1
28     static_assert(sizeof(Empty) >= 1);
29 
30     // 至少需要多一个字节以给 e 唯一地址
31     static_assert(sizeof(X) >= sizeof(int) + 1);
32 
33     // 优化掉空成员
34     std::cout << "sizeof(Y) == sizeof(int) is " << std::boolalpha
35               << (sizeof(Y) == sizeof(int)) << '\n';
36 
37     // e1 与 e2 不能共享同一地址,因为它们拥有相同类型,尽管它们标记有 [[no_unique_address]]。
38     // 然而,其中一者可以与 c 共享地址。
39     static_assert(sizeof(Z) >= 2);
40 
41     // e1 与 e2 不能拥有同一地址,但它们之一能与 c[0] 共享,而另一者与 c[1] 共享
42     std::cout << "sizeof(W) == 2 is " << (sizeof(W) == 2) << '\n';
43 }
44 
45 // output:
46 // sizeof(Y) == sizeof(int) is false
47 // sizeof(W) == 2 is false
复制代码

 

posted @   Asp1rant  阅读(175)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示