Considere el siguiente código:

#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;
}

A medida que crecieron los compiladores modernos y ahora vigilan los errores tontos del programador, realizan un seguimiento de las variables unitarias. Sin embargo, este código C ++ los confunde. Hasta ahora, obtengo los siguientes resultados:

                        (1)      (2)
g++ 5.3.1
clang++ 3.7              ✔
Solaris Studio 12.5      ✔

Como puede ver, CLang y solstudio pueden detectar solo el caso (1) e ignorar el caso (2), mientras que g ++ ignora ambos. ¿Hay alguna complicación para detectarlo en el caso (2)? ¿Por qué g ++ es tan malo en esto?

Opciones del compilador que utilicé:

$ 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
9
myaut 8 feb. 2017 a las 19:00

2 respuestas

La mejor respuesta

En primer lugar: ambos compiladores solo diagnostican el primer delito, es decir, solo informan el primer uso no inicializado de a. Entonces, para obtener una advertencia para la segunda, debemos eliminar esa primera línea:

#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;

}

Ahora vemos dos peculiaridades del compilador no relacionadas: clang no incluye -Wconditional-uninitialized en -Wall y -Wextra. Si habilita eso, do recibirá una advertencia en std::cout porque potencialmente imprime una variable no inicializada.

gcc por otro lado, solo rastrea las variables no inicializadas cuando el optimizador está habilitado, probablemente para acelerar la compilación de compilaciones de depuración. Con -O2 -Wall, gcc 6 lanza una advertencia en ambos casos, aunque sin señalar la ubicación exactamente como lo hace clang en el segundo caso. (gcc <= 5.3 no advierte sobre el segundo caso como observó, por lo que parece que se implementó recientemente).

Entonces TL; DR: No invocaste correctamente a tus compiladores.

3
Baum mit Augen 3 mar. 2017 a las 22:25

std::max toma sus argumentos por const &, mientras que el operador de transmisión << para int s toma el int por valor. Pasar un objeto no inicializado por referencia es legal: por ejemplo, si la función solo toma su dirección, todo está bien. Por lo tanto, la advertencia al pasar a a std::max podría ser fácilmente un falso positivo.

12
Angew is no longer proud of SO 8 feb. 2017 a las 16:04