现代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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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工具