2015-04-25 14 views
19

Quando si creano variabili locali, è corretto utilizzare (const) auto& o auto?C++ auto & vs auto

es .:

SomeClass object; 
const auto result = object.SomeMethod(); 

o const auto& result = object.SomeMethod();

Dove SomeMethod() restituisce un valore non-primitivo - forse un altro tipo definito dall'utente. La mia comprensione è che const auto& result è corretto poiché il risultato restituito da SomeMethod() chiamerebbe il costruttore di copie per il tipo restituito. Perfavore, correggimi se sbaglio.

E per i tipi primitivi? Presumo che const auto sum = 1 + 2; sia corretto.

Questo si applica anche alla gamma basata su cicli?

for(const auto& object : objects) 
+1

Consiglio vivamente di leggere questo: https://www.safaribooksonline.com/library/view/effective-modern-c/9781491908419/ch01.html I primi due capitoli sono gratuiti e descrivono la deduzione del tipo di modello, che è essenzialmente come funziona 'auto' (tranne il caso particolare di' initializer_list's, che non è dedotto in un contesto di template), quindi la deduzione di tipo 'auto'. – vsoftco

risposta

12

Sì, è corretto utilizzare auto e auto& per le variabili locali. Quando si ottiene il tipo di ritorno di una funzione, è anche corretto usare auto&. Questo vale anche per i range basati su loop.

regole generali per l'utilizzo auto sono:

  • Scegli auto x quando si desidera lavorare con copie.
  • Scegliere auto &x quando si desidera lavorare con gli elementi originali e possono modificarli.
  • Scegliere auto const &x quando si desidera lavorare con gli elementi originali e sarà non li modifica.

Ulteriori informazioni sull'identificatore here.

3

auto utilizza lo stesso meccanismo di tipo detrazione come modelli, l'unica eccezione che io sono consapevole di essere quella di liste brace-init, che si deducono dalla auto come std::initializer_list, ma non dedotta in un contesto modello.

auto x = expression; 

opere prima strippaggio tutte qualificatori riferimento e cv dal tipo dell'espressione destra, quindi corrispondenti al tipo. Ad esempio, se si dispone di const int& f(){...}, auto x = f(); deduce x come int e nonconst int&.

L'altra forma,

auto& x = expression 

non elimina CV-qualificazioni, quindi, usando l'esempio precedente, auto& x = f() deduce x come const int&. Le altre combinazioni aggiungono solo qualificatori di cv.

Se si desidera che il proprio tipo venga sempre dedotto con qualificazioni cv-ref, utilizzare il famigerato decltype(auto) in C++ 14, che utilizza le regole di deduzione del tipo decltype.

Quindi, in poche parole, se si desidera copiare, utilizzare auto, se si desidera riferimenti, utilizzare auto&. Utilizzare const ogni volta che si desidera ulteriore const -ness.


EDIT V'è un caso d'uso aggiuntivo,

auto&& x = expression; 

che utilizza le regole di riferimento-collasso, proprio come nel caso di riferimenti di inoltro nel codice del modello. Se expression è un lvalue, allora x è un riferimento lvalue con i qualificatori cv di expression. Se expression è un valore rvalore, allora x è un riferimento di rvalue.

+0

@Potatoswatter Grazie, modificato. In realtà mi chiedo del cv per "rvalues". C'è un modo semplice di test? E come puoi avere un rv qualificato per CV? Sulla funzione return cv viene scartato. – vsoftco

+0

No, non viene scartato sui ritorni delle funzioni.Viene scartato per i valori preregistrati di tutti i tipi scalari (C++ 14 [e altre edizioni] §5/6). Puoi ottenerne una usando una chiamata di funzione o una notazione cast. Gli xval di qualifica per Cv funzionano come qualsiasi altra cosa: 'auto && x = std :: move < const int > (5);' dichiarerà 'int const && x', sebbene vengano usati raramente. – Potatoswatter

+0

@Potatoswatter grazie, hai ragione, mio ​​errore. Ho provato prima con i POD, nel qual caso il cv è scartato e ho pensato che fosse il caso generale. Ovviamente non dovrebbe essere scartato, dal momento che in generale si potrebbe voler preservare il cv (ad esempio in modo che non si possa chiamare la funzione membro non const sui ritorni rvalue). – vsoftco

30

auto e auto && copertura maggior parte dei casi:

  • Usa auto quando hai bisogno di una copia locale. Questo non produrrà mai un riferimento. Il costruttore di copia (o spostamento) deve esistere, ma potrebbe non essere richiamato, a causa dell'elegazione copia elision.

  • Utilizzare auto && quando non si cura se l'oggetto è locale o meno. Tecnicamente, questo produrrà sempre un riferimento, ma se l'inizializzatore è temporaneo (ad esempio, la funzione restituisce per valore), si comporterà essenzialmente come il tuo oggetto locale.

    Inoltre, auto && non garantisce che l'oggetto sarà anche modificabile. Dato un oggetto o riferimento const, dedurrà const. Tuttavia, spesso si assume modificabilità, dato il contesto specifico.

auto & e auto const & sono un po 'più specifico:

  • auto & garanzie che si desidera condividere la variabile con qualcos'altro. È sempre un riferimento e mai temporaneo.

  • auto const & è come auto &&, ma fornisce l'accesso di sola lettura.

Che dire per i tipi primitivi/non-primitivi?

Non c'è differenza.

Questo si applica anche alla gamma basata su cicli?

Sì. Applicazione dei principi sopra riportati,

  • Utilizzare auto && per la possibilità di modificare e scartare i valori della sequenza all'interno del ciclo.(Ovvero, a meno che il contenitore non disponga di una vista di sola lettura, ad esempio std::initializer_list, nel qual caso sarà effettivamente un .)
  • Utilizzare auto & per modificare i valori della sequenza in modo significativo.
  • Utilizzare auto const & per l'accesso in sola lettura.
  • Utilizzare auto per lavorare con copie (modificabili).

Hai anche menzionato auto const senza riferimento. Funziona, ma non è molto comune perché raramente c'è un vantaggio dell'accesso in sola lettura a qualcosa che già possiedi.

0

Quando si creano variabili locali, è corretto utilizzare (const) auto & o auto?

Sì. L'auto non è altro che un tipo dedotto dal compilatore, quindi utilizza i riferimenti in cui normalmente utilizzi i riferimenti e le copie locali (automatiche) in cui normalmente utilizzi le copie locali. L'uso o meno di un riferimento è indipendente dalla deduzione del tipo.

Dove SomeMethod() restituisce un valore non primitivo, forse un altro tipo definito dall'utente. La mia comprensione è che il risultato const auto & è corretto poiché il risultato restituito da SomeMethod() chiamerebbe il costruttore di copie per il tipo restituito. Perfavore, correggimi se sbaglio.

Note legali? Sì, con il const. La migliore pratica? Probabilmente no, no. Almeno, non con C++ 11. Soprattutto, se il valore restituito da SomeMethod() è già temporaneo. Avrai voglia di conoscere C++ 11 semantica spostare, copiare l'elisione, e restituire l'ottimizzazione del valore: https://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by-value/

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=199

https://isocpp.org/wiki/faq/ctors#return-by-value-optimization

Che dire per i tipi primitivi? Suppongo const auto sum = 1 + 2; è corretta.

Sì, questo va bene.

Questo si applica anche alla gamma basata su cicli?

per (const auto & oggetto: oggetti)

Sì, questo è anche bene. Scrivo questo tipo di codice al lavoro tutto il tempo.