2015-10-08 20 views
5

Nel libro di Scott Meyer Effective moderna C++ si legge, che:auto e static_casts - le buone pratiche

std::vector<bool> features(const Widget& w); 
Widget w; 
… 
bool highPriority = features(w)[5]; 
… 
processWidget(w, highPriority); 

e un'opzione con auto

auto highPriority = features(w)[5]; 

che provoca un comportamento indefinito, a causa della Infatti, features() restituisce std::vector<bool>, che utilizza l'oggetto proxy di tipo std::vector<bool>::reference quando restituisce un valore da opearator[].

Come soluzione a questo si consiglia di non interrompere l'utilizzo di auto, ma utilizzando static_casts.

Così Scott Meyers consigli d'uso:

auto highPriority = static_cast<bool>(features(w)[5]); 

invece di:

bool highPriority = features(w)[5]; 

La mia domanda è: Qual è la vera differenza tra i due? Secondo me sono entrambi uguali, perché entrambi i metodi rendono più difficile il refactoring nello stesso modo (cambiare il tipo di valore di ritorno nelle funzioni della funzione non rende la variabile highPriority un tipo diverso) e la seconda è più breve da scrivere.

+1

Solo un sospetto, ma in cima alla mia testa non riesco a pensare a una differenza funzionale, e l'unica ragione di Scott potrebbe essere la coerenza - non ha sostenuto l'uso di 'auto x =' per pratico tutto da qualche parte nello stesso libro ...? (O forse era un articolo online che ho visto ...) –

+3

@TonyD Sì, la coerenza è probabilmente la ragione. Suggerisce di "preferire' auto' a dichiarazioni di tipo esplicite "nell'articolo 5 – TartanLlama

+1

Direi che la prima soluzione dice esplicitamente al lettore" la cosa non è un bool, ma voglio che sia un bool ". La seconda soluzione di solito dice al lettore "che è un bool o almeno può essere usato come tale" ma il problema è che la maggior parte dei lettori lo legge come "quello è un bool" e probabilmente "hey, ora abbiamo" auto ", quindi scriviamo 'auto highPriority = features (w) [5];'! ", e boom. Anche se entrambe le soluzioni sono tecnicamente identiche, il lettore è avvisato nel primo caso che potrebbe esserci un problema con l'uso di 'features (w) [5]' direttamente. A proposito, lo stesso problema si verifica con cose come i modelli di espressione. – leemes

risposta

7

Se non vi piace l'interfaccia di features, è possibile nascondere la bruttezza in una funzione di supporto

bool is_high_priority(const Widget& w) 
{ return features(w)[5]; } 

e ora i tuoi

auto highPriority = is_high_priority(w); 

funziona come previsto.

+0

Potresti dirmi dov'è !! Proveniente da? È qualche nuovo operatore o qualcosa del genere? È una caratteristica specifica del compilatore? In qualche modo non riesco a trovarlo ovunque – DawidPi

+0

Sono solo due negazioni di seguito. '! x' trasformerà' x' in un 'bool' (confrontandolo con 0), ma con il valore opposto. '!! x' invertirà nuovamente il valore di'! x', producendo 'false' per zero e 'true' per non-zero. –

5

Con features una funzione che restituisce un std::vector<bool>,

auto highPriority = features(w)[5]; 

memorizza un riferimento logico. L'oggetto memorizzato si riferisce a un vettore che non esiste più. Usarlo comporta quindi comportamento indefinito.

Invece fanno

bool const highPriority = features(w)[5]; 

o

auto const highPriority = !!features(w)[5]; 

o, come Scott raccomanda – ma è di gran lunga troppo prolisso per i miei gusti – utilizzare un static_cast.

L'oggetto memorizzato è ora bool.

Non c'è alcuna differenza funzionale tra questi tre modi di esprimere la stessa dichiarazione. Le uniche differenze sono non funzionali: a mio avviso la verbosità inutile di static_cast e una possibilità che lo !! possa sopprimere un avvertimento stupido sulle prestazioni, da un compilatore comune.

0

Quando si utilizza l'auto, lo si deduce automaticamente come il tipo restituito da highPriority che è un riferimento a un valore booleano.Il fatto è che highPriority non restituisce un riferimento a un bool ma a un oggetto di riferimento std :: vector ::. ('reference' è una classe annidata dentro std :: vector). std :: vector :: reference è una "classe proxy", una classe che emula il comportamento di un altro tipo. Non solo è una classe proxy ma una classe proxy "invisibile". Tali classi non funzionano bene con l'auto. Auto non può dedurre correttamente il tipo di una classe proxy invisibile. Ma static_cast impone una conversione ad alta priorità in un bool. Questo evita comportamenti indefiniti.

+0

questo è quello che ho detto. Ho chiesto 2 possibili soluzioni e perché Scott Meyers preferisce il primo uno – DawidPi

+0

Non lo preferisce. C'è una differenza. Le sue parole ... "il cast cambia il tipo dell'espressione in bool, che auto quindi deduce come tipo per highPriority .In runtime, lo std :: vector :: oggetto di riferimento restituito da std :: vector : : operator [] esegue la conversione in bool che supporta ... " Quindi il cast statico è necessario per cambiare il tipo in un bool FIRST per tutto il resto. – dspfnder

+1

esattamente lo stesso cast viene eseguito, quando si dice 'bool highPrio ...' Nel primo e nel secondo tentativo non c'è differenza nell'esecuzione. In entrambe le soluzioni il cast è fatto ed è lo stesso cast. Uno è esplicito ed è implicito che è l'unica differenza. Il risultato è lo stesso. – DawidPi