C++临时对象构造是否先于成员函数实参求值?多标准版本问询
关于C++宏中构造函数与参数求值顺序的问题
不同C++标准下的结果存在差异,具体情况如下:
C++17及以后版本
在C++17及更新的标准里,成员函数调用的左侧对象表达式(也就是AbortHelper(__FILE__, __LINE__))会被完整求值,且一定会先于成员函数的实参(msg)求值。
这意味着当你写ABORT(GenerateAbortMsg());时,AbortHelper的构造函数肯定会先执行,对象创建完成后才会去调用GenerateAbortMsg()。哪怕这个函数抛出异常,AbortHelper的析构函数也会被触发,进而执行终止程序的逻辑,完全符合你的需求。
C11/C14版本
这两个版本的标准没有明确规定成员函数调用时,对象表达式和实参的求值顺序。编译器可以自由选择先计算msg,再创建AbortHelper对象;也可以反过来执行。
如果编译器选择先求值GenerateAbortMsg(),那要是这个函数抛出异常,AbortHelper的构造函数根本没机会执行,自然不会触发析构函数的终止逻辑,你的需求就无法得到保证。
C++03及更早版本
这些旧标准的规则和C11/C14一致,同样没有定义成员函数调用中对象表达式和实参的求值顺序,编译器可自行决定求值顺序,所以同样无法保证构造函数先于msg执行。
兼容旧标准的解决办法
如果要在C++17之前的版本实现你的需求,可以把宏改成这样:
#define ABORT(msg) do { \ AbortHelper helper(__FILE__, __LINE__); \ helper.Report(msg); \ } while(0)
这种写法里,helper对象会在msg求值前就被创建,不管哪个C++版本,都能确保构造函数先执行,哪怕msg抛出异常,析构函数也能触发终止逻辑。
内容的提问来源于stack exchange,提问作者Bwmat
相关产品推荐
相关产品推荐

