2012-03-18 6 views
6

Compilar este código con g ++ 4.7.0 (-Wall -Wextra -Werror -Wconversion -std=c++11):inicialización uniforme con {} informes de variable no utilizada

#include <iostream> // std::cout, std::endl 
#include <string> // std::string 
#include <utility> // std::move 

void out(std::string const &message) 
{ 
    static int count{0}; 
    std::cout << count++ << " = " << message << std::endl; 
} 

struct Foo 
{ 
    Foo()       {out("constructor");} 
    ~Foo()       {out("destructor");} 
    Foo(Foo const &)    {out("copy constructor");} 
    Foo & operator=(Foo const &) {out("copy via assignment"); return *this;} 
    Foo(Foo &&)     {out("move constructor");} 
    Foo & operator=(Foo &&)  {out("move via assignment"); return *this;} 
}; 

int main() 
{ 
    auto bar{std::move(Foo())}; 
    out("exiting main"); 
} 

... resultados en el error siguiente:

error: unused variable 'bar' [-Werror=unused-variable] 

I pueden quitar el error cambiando la inicialización bar a cualquiera de los siguientes:

/* 0 */ auto bar(std::move(Foo())); 
/* 1 */ Foo bar{std::move(Foo())}; 
/* 2 */ Foo bar(std::move(Foo())); 
/* 3 */ auto bar = std::move(Foo()); 
/* 4 */ Foo bar = std::move(Foo()); 
/* 5 */ auto bar __attribute__((unused)) {std::move(Foo())}; 

Una vez que la inicialización bar se ha cambiado, la salida es siempre :

0 = constructor 
1 = move constructor 
2 = destructor 
3 = exiting main 
4 = destructor 

¿Por qué la bar informe original de inicialización de una variable no utilizada?

+0

¿Qué sucede en el tiempo de ejecución si utiliza la versión "incorrecta" del código y compila sin '-Werror'? –

+0

@JohnZwinck el ** error ** se convierte en ** advertencia ** –

+0

Parece que es solo un caso no controlado en la lógica de advertencia de variable no utilizada. Archivo un error con gcc. – bames53

Respuesta

8
auto bar{std::move(Foo())}; 

Después de esta declaración, bar es de tipo std::initializer_list<Foo>, que tiene operaciones de copia triviales/mover y destructor. Sus otras declaraciones

auto bar(std::move(Foo())); 
Foo bar{std::move(Foo())}; 
Foo bar(std::move(Foo())); 
auto bar = std::move(Foo()); 
Foo bar = std::move(Foo()); 

de declarar como barFoo o Foo&&, que suprime la advertencia, ya que tiene funciones miembro especiales no triviales.

Por lo general, no desea la inicialización reforzada con auto a menos que tenga la intención específica de crear un objeto std::inializer_list.

+0

Esto tiene perfecto sentido. Estaba asumiendo erróneamente que GCC usaría 'Foo' como tipo cuando en realidad no tiene ninguna razón para hacerlo. –

+1

De hecho, probé 'auto bar {5}; cout << typeid (bar) << endl; 'y da como resultado' St16initializer_listIiE', ¡así que definitivamente tienes razón! –

2

Bueno, bares sin uso. Es posible que desee archivar un defecto para el compilador, ya que esto parece pasar desapercibido en las otras situaciones.

+2

'bar' no se usa, pero pensé que el compilador no informaba advertencias de variables no utilizadas para tipos no triviales. –

+0

¡Lo que el compilador use para producir advertencias depende del compilador! Mi posición personal es que quiero que se marquen todas las variables no utilizadas cuando solicite que se marquen las variables no utilizadas. En mi kit de herramientas tengo una plantilla de función simple para los casos en que me refiero a los objetos que no se utilizarán: 'plantilla void use (T const &) {}'. –

Cuestiones relacionadas