请考虑以下代码:
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> v{{1, 2, 3}};
int a;
std::cout << a << std::endl; // 1
for (const int x : v) {
a = std::max(a, x); // 2
}
std::cout << a << std::endl;
return 0;
}
随着现代编译器的发展,现在我们仍然密切关注程序员的愚蠢错误,他们会跟踪整合变量。但是,这个C ++代码会让他们感到困惑。到目前为止,我得到了以下结果:
(1) (2)
g++ 5.3.1
clang++ 3.7 ✔
Solaris Studio 12.5 ✔
正如您所看到的,CLang和solstudio只能检测case(1)并忽略case(2),而g ++忽略了两者。在案例(2)中是否存在检测它的复杂情况?为什么g ++在这方面如此糟糕?
我使用的编译器选项:
$ g++-5 -std=c++11 -Wall -Wpedantic -pedantic -Wextra \
-Wuninitialized -Wmaybe-uninitialized aisa.cpp
$ clang++ -std=c++11 -Wall -Wpedantic -pedantic -Wextra -Wuninitialized aisa.cpp
$ CC -std=c++11 -xprevise aisa.cpp
答案 0 :(得分:12)
std::max
的参数为const &
,而<<
的流式算子int
的值为int
。通过引用传递未初始化的对象是合法的:例如,如果函数只是获取其地址,则一切都很好。因此,将a
传递给std::max
时的警告很容易成为误报。
答案 1 :(得分:3)
首先:两个编译器只诊断第一次攻击,即他们只报告第一次未初始化使用a
。因此,为了获得第二条警告,我们需要删除第一行:
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> v{{1, 2, 3}};
int a;
for (const int x : v) {
a = std::max(a, x); // 2
}
std::cout << a << std::endl;
return 0;
}
现在我们看到两个不相关的编译器怪癖: clang 在-Wconditional-uninitialized
和-Wall
中不包含-Wextra
。如果启用该功能,则执行会在std::cout
处收到警告,因为它可能会打印未初始化的变量。
gcc 仅在启用优化程序时跟踪未初始化的变量,可能会加快编译构建的编译速度。使用-O2 -Wall
时,gcc 6会在两种情况下都发出警告,但没有像第二种情况那样精确定位该位置。 (gcc&lt; = 5.3并没有像你观察到的那样对第二种情况发出警告,所以最近似乎已经实施了。)
所以TL; DR:你没有正确地调用你的编译器。