C++ 异常抛出宏中lambda与__attribute__的作用及使用优势咨询
1. __attribute__ 标记的作用
这是GCC/Clang编译器特有的属性标记,这里用到的两个参数作用非常明确:
cold:告诉编译器这个函数是冷路径,也就是几乎不会被执行到的代码。编译器优化时会优先把性能资源倾斜到其他高频执行的代码上,同时会把这个函数的二进制指令放到程序的「冷代码段」,不和常用的业务代码挤在一起,避免占用CPU缓存,提升主流程的执行效率。noinline:禁止编译器把这个函数的代码内联到调用位置。如果没有这个标记,编译器可能会把lambda的代码直接展开到宏调用的地方,反而让冷路径的代码混进了主流程的热路径里,就浪费了cold属性的优化效果。
2. 用lambda实现的核心优势
不用lambda确实也能实现同样的抛异常逻辑,但用lambda有几个不可替代的实用好处:
作用域完全隔离
lambda自带独立的作用域,里面定义的exception_type别名、std::ostringstream变量ss,完全不会和宏调用位置的同名变量冲突。虽然do...while(0)也有块作用域,但lambda相当于多了一层隔离,哪怕后续宏的逻辑加了更多临时变量,也完全不用担心污染外部作用域。
可以方便地附加函数属性
如果不用lambda,你没法给一段零散的代码块加cold、noinline这种编译器属性,这些属性只能加在函数上。如果为了这段抛异常的逻辑单独定义全局函数,不仅会有重名风险,而且没法直接使用宏调用位置的局部变量(比如错误信息要拼接宏调用处的局部变量,全局函数根本拿不到)。lambda刚好完美解决了这个问题:就地定义函数、可以通过捕获直接使用外部变量、还能自由添加编译器属性。
精简热路径代码体积
加了noinline之后,宏展开后的主流程里只有一句调用lambda的指令,原本拼接错误信息、抛异常的大段代码都被挪到了冷段里,主流程的代码体积更小,CPU缓存命中率更高,程序正常运行(不抛异常)的时候速度更快。
可以打个通俗的比方:你平时用的书包只放每天要用到的课本、文具,那些一年用不到几次的换季衣服、运动装备,都单独放到家里的储物间,这样你平时背书包更轻便,找东西也更快。这里lambda就是那个储物间,把很少用到的抛异常逻辑都收进去,不占用主流程的「背包空间」。
内容的提问来源于stack exchange,提问作者DonBaka
相关产品推荐
相关产品推荐

