2012-03-18 13 views
6

przygotowanie tego kodu z g ++ 4.7.0 (-Wall -Wextra -Werror -Wconversion -std=c++11):Uniform inicjalizacji z {} raportowania niewykorzystaną zmienną

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

... wyniki w następujący błąd:

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

można usunąć błąd przez zmianę inicjalizacji bar na jedną z poniższych:

/* 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())}; 

Po inicjalizacji bar została zmieniona, wyjście jest zawsze:

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

Dlaczego oryginalny bar raport inicjalizacja nieużywaną zmienną?

+0

Co dzieje się w środowisku wykonawczym, jeśli używasz "złej" wersji kodu i kompilujesz bez '-Werror'? –

+0

@JohnZwinck ** błąd ** zmienia się w ** ostrzeżenie ** –

+0

Wydaje się, że jest to po prostu nieobsłużony przypadek w nieużywanej logice ostrzegawczej zmiennej. Zgłoś błąd za pomocą gcc. – bames53

Odpowiedz

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

Po tej deklaracji, bar jest typu std::initializer_list<Foo>, który ma trywialne operacje kopiuj/ruch i destruktora. Twoje inne deklaracje

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()); 

DECLARE bar jak Foo lub Foo&&, który tłumi ostrzeżenie, ponieważ ma nietrywialnych specjalnych funkcji Członka.

Zazwyczaj nie chcesz, aby inicjacja była wzmocniona z auto, chyba że masz zamiar utworzyć obiekt std::inializer_list.

+0

To ma sens. Błędnie założyłem, że GCC użyłoby 'Foo' jako typu, gdy faktycznie nie ma powodu. –

+1

W rzeczywistości próbowałem 'auto bar {5}; cout << typid (bar) << endl; 'i wypisuje' St16initializer_listIiE', więc zdecydowanie masz rację! –

2

Cóż, barjest nieużywany. Być może zechcesz zgłosić defekt dla kompilatora, który w innych sytuacjach wydaje się być błędnie niewykryty.

+2

'bar' jest nieużywany, ale myślałem, że kompilator nie zgłosił nieużywanych zmiennych ostrzeżeń dla nietrywialnych typów. –

+0

Cokolwiek kompilator używa do generowania ostrzeżeń, zależy to od kompilatora! Moją osobistą pozycją jest to, że chcę, aby wszystkie niewykorzystane zmienne były oflagowane, gdy poproszę o oznaczenie nieużywanych zmiennych. W moim zestawie narzędzi mam prosty szablon funkcji dla przypadków, w których mam na myśli obiekty, które mają być niewykorzystywane: 'template void use (T const &) {}'. –