为什么选择int; a = std :: max(a,x)不会发出"未初始化"警告

mya*_*aut 9 c++ static-analysis compiler-warnings

请考虑以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

随着现代编译器的发展,现在仍然密切关注程序员的愚蠢错误,他们会跟踪整合变量.但是,这个C++代码会让他们感到困惑.到目前为止,我得到以下结果:

                        (1)      (2)
g++ 5.3.1
clang++ 3.7              ?
Solaris Studio 12.5      ?
Run Code Online (Sandbox Code Playgroud)

如您所见,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
Run Code Online (Sandbox Code Playgroud)

Rei*_*ica 12

std::max通过接受它的参数const &,而流媒体运营商<<intS可在int按值.通过引用传递未初始化的对象是合法的:例如,如果函数只是获取其地址,则一切都很好.因此,传递a给警告std::max很容易就是误报.


Bau*_*gen 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;

}
Run Code Online (Sandbox Code Playgroud)

现在我们看到两个不相关的编译器怪癖:clang不包含-Wconditional-uninitializedin-Wall-Wextra。如果启用该功能,您收到警告,std::cout因为它可能会打印未初始化的变量。

另一方面,gcc仅在启用优化器时跟踪未初始化的变量,可能是为了加快调试版本的编译速度。对于-O2 -Wall,gcc 6 在这两种情况下都会发出警告,但不会像在第二种情况下 clang 那样准确地指出位置。(gcc <= 5.3 不会对您观察到的第二种情况发出警告,因此似乎是最近才实施的。)

所以 TL;DR:您没有正确调用编译器。