我最近在这样的代码中遇到了一个错误
class C
{
public:
// foo return value depends on C's state
// AND each call to foo changes the state.
int foo(int arg) /*foo is not const-qualified.*/ {}
private:
// Some mutable state
};
C c;
bar(c.foo(42), c.foo(43))
最后一次调用在不同平台上的行为有所不同(由于参数评估的顺序不确定,因此完全合法),并且我修复了该错误。
但是其余的代码库很大,我想发现这种类型的所有其他UB。
在此类情况下,GCC,Clang或MSVS是否有特殊的编译器警告?
预防这种错误的意识形态和轻量级方法是什么?
答案 0 :(得分:1)
Argument order evaluation是未指定,而不是未定义。
几乎所有C ++运算符的操作数求值顺序(包括函数调用表达式中的函数自变量的求值顺序和任何表达式中子表达式的求值顺序)未指定。编译器可以按任何顺序求值操作数,并且当再次求同一个表达式时可以选择其他顺序。
由于未指定行为而不是未定义行为,因此不需要编译器为其发出诊断。
GCC和Clang没有任何常规的编译器选项可以发出针对未指定行为的诊断。
在GCC中,有一个fstrong-eval-order
选项可以执行此操作:
按照C ++ 17的要求,以从左到右的顺序评估成员访问,数组下标和移位表达式,并以从右到左的顺序评估赋值。默认启用
-std=c++17
。-fstrong-eval-order=some
仅启用成员访问和移位表达式的排序,这是不包含-std=c++17
的默认设置。
还有-Wreorder
选项(仅适用于C ++和Objective-C ++):
当代码中给定的成员初始化程序的顺序与执行它们的顺序不匹配时发出警告
但是我认为这些选项对您的具体情况没有帮助。
在下面的语句中,如果要在第二个参数之前对第一个参数求值:
bar(c.foo(42), c.foo(43))
简单的方法是首先将c.foo(42)
和c.foo(43)
的结果存储在中间变量中,然后调用bar()
。 (关闭编译器优化,以避免编译器对语句进行任何重新排序!)
auto var1 = c.foo(42);
auto var2 = c.foo(43);
bar(var1, var2);
我想这就是您必须修复该错误的方式。