C ++ auto e vs auto


91

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

per esempio:

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 copia per il tipo restituito. Perfavore, correggimi se sbaglio.

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

Questo vale anche per i loop basati su intervallo?

for(const auto& object : objects)

1
Ti consiglio vivamente di leggere questo: safaribooksonline.com/library/view/effective-modern-c/… I primi due capitoli sono gratuiti e descrivono la deduzione del tipo di modello, che è essenzialmente il modo in cui autofunziona (tranne il caso particolare di initializer_lists, che sono non dedotto in un contesto di modello), quindi autodigitare deduction.
vsoftco

Risposte:


107

autoe auto &&coprono la maggior parte dei casi:

  • Utilizzare autoquando è necessaria una copia locale. Questo non produrrà mai un riferimento. Il costruttore di copia (o spostamento) deve esistere, ma potrebbe non essere chiamato, a causa dell'ottimizzazione dell'elisione della copia .

  • Usalo auto &&quando non ti interessa 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 nemmeno che l'oggetto sarà modificabile. Dato un constoggetto o un riferimento, dedurrà const. Tuttavia, si presume spesso la modificabilità, dato il contesto specifico.

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

  • auto &garantisce che stai condividendo la variabile con qualcos'altro. È sempre un riferimento e mai temporaneo.

  • auto const &è simile auto &&, ma fornisce l'accesso in sola lettura.

E per i tipi primitivi / non primitivi?

Non c'è differenza.

Questo vale anche per i loop basati su intervallo?

Sì. Applicando i principi di cui sopra,

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

Parli anche auto constsenza riferimenti. Funziona, ma non è molto comunemente usato perché raramente c'è un vantaggio nell'accesso in sola lettura a qualcosa che già possiedi.


Sutter dice che auto e tiene traccia della costanza
Jesse Pepper

1
@JessePepper Sì. (È un po 'strano fare appello all'autorità però.) Ti riferisci a una parte specifica di questo?
Potatoswatter

In sostanza auto&sembra essere una buona scelta. Ma usando const auto&quando vuoi aggiungere costanza che non è già presente. auto&&serve per l'inoltro, cosa che credo avvenga più spesso di quanto pensi Sutter. Ad esempio, potresti voler memorizzare un valore restituito da auto&&e poi "inoltrarlo" a due cose, come std :: cout per vedere il valore per il debug e passarlo anche a qualche altra funzione. Usavo auto && più spesso, ma sono stato morso da esso una o due volte quando ha fatto cose inaspettate. Vorrei aver prestato più attenzione a cosa è andato storto!
Jesse Pepper

@JessePepper Sì, auto&&è correlato a una caratteristica del linguaggio mancante, che dovrebbe consentire di dividere qualsiasi istruzione in dichiarazioni più piccole. La parte mancante è l'estensione a vita ... Ho fatto un bel po 'di sforzi per risolvere questo problema ma nessuno se ne è accorto. Non mettere troppe scorte in punditry :)
Potatoswatter

Su auto const: potrebbe essere più naturale scrivere auto const x = fn (); se sai che la funzione non restituisce un riferimento e vuoi che l'oggetto x non cambi, per evitare bug, o documenta il suo utilizzo nell'ambito. Allo stesso modo in cui normalmente non scriverebbe: const int & x = 1; Ma auto const & fornisce risultati equivalenti a causa delle regole di estensione della durata per i riferimenti dichiarati in questo modo.
Spacen Jasset

47

Sì, è corretto usare autoe auto&per le variabili locali. Quando si ottiene il tipo restituito di una funzione, è anche corretto da usare auto&. Questo vale anche per i loop basati su intervallo.

Le regole generali per l'utilizzo autosono:

  • Scegli auto xquando vuoi lavorare con le copie.
  • Scegli auto &xquando vuoi lavorare con gli elementi originali e puoi modificarli.
  • Scegli auto const &xquando vuoi lavorare con gli elementi originali e non li modificherai.

Puoi leggere di più sullo specificatore automatico qui .


10

autoutilizza lo stesso meccanismo di deduzione del tipo dei modelli, l'unica eccezione di cui sono a conoscenza è quella delle liste di parentesi graffe, che vengono dedotte da autoas std::initializer_list, ma non dedotte in un contesto di modello.

auto x = expression;

funziona eliminando prima tutti i qualificatori di riferimento e cv dal tipo dell'espressione a destra, quindi facendo corrispondere il tipo. Per esempio, se avete const int& f(){...}quindi auto x = f();deduce xcome int, e non const int& .

L'altra forma,

auto& x = expression

non rimuove i qualificatori cv, quindi, usando l'esempio sopra, auto& x = f()deduce xcome const int&. Le altre combinazioni aggiungono semplicemente qualificatori cv.

Se vuoi che il tuo tipo sia sempre dedotto con qualificatori cv-ref, usa il famigerato decltype(auto)C ++ 14, che usa le decltyperegole di deduzione del tipo.

Quindi, in poche parole, se vuoi copie, usa auto, se vuoi riferimenti, usa auto&. Usalo constogni volta che vuoi essere aggiuntivo const.


EDIT C'è un caso d'uso aggiuntivo,

auto&& x = expression;

che utilizza le regole di compressione dei riferimenti, come nel caso dell'inoltro dei riferimenti nel codice del modello. Se expressionè un lvalue, allora xè un riferimento lvalue con i qualificatori cv di expression. Se expressionè un rvalue, allora xè un riferimento rvalue.


@ Potatoswatter Grazie, modificato. In realtà mi chiedo del cv per rvalues. Esiste un modo semplice per eseguire il test? E come puoi avere un rvalue qualificato in cv? Al ritorno della funzione cv viene scartato.
vsoftco

No, non viene scartato nei ritorni di funzione. Viene scartato per i prvalues ​​di tutti i tipi scalari (C ++ 14 [e altre edizioni] §5 / 6). Puoi ottenerne uno usando una chiamata di funzione o una notazione cast. I valori x qualificati per cv funzionano come qualsiasi altra cosa: auto && x = std::move< const int >( 5 );dichiareranno int const && x, sebbene siano usati raramente.
Potatoswatter

@ Potatoswatter grazie, hai ragione, errore mio. Ho provato prima con i POD, nel qual caso il cv viene 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, quindi non si può chiamare la funzione membro non-const su rvalue ritorna).
vsoftco

Scartato per i tipi scalari. I POD possono essere classi. Ad ogni modo, è un angolo hacker dell'intersezione tra il modello di espressione e il modello a oggetti.
Potatoswatter

2

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

Sì. L'auto non è altro che un tipo dedotto dal compilatore, quindi usa i riferimenti dove normalmente useresti i riferimenti e le copie locali (automatiche) dove normalmente useresti le copie locali. L'utilizzo o meno di un riferimento è indipendente dalla detrazione del tipo.

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 copia per il tipo restituito. Perfavore, correggimi se sbaglio.

Legale? Sì, con il const. La migliore pratica? Probabilmente no, no. Almeno, non con C ++ 11. Soprattutto no, se il valore restituito da SomeMethod () è già temporaneo. Ti consigliamo di conoscere la semantica di spostamento C ++ 11, l'elisione della copia e l'ottimizzazione del valore restituito: https://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by- valore/

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

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

E per i tipi primitivi? Assumo const auto sum = 1 + 2; è corretta.

Sì, va bene.

Questo vale anche per i loop basati su intervallo?

for (const auto & object: objects)

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.