Dovrei usare la nuova funzionalità "auto" di C ++ 11, specialmente nei loop?


20

Quali sono i pro / contro nell'usare la autoparola chiave, specialmente in per i loop?

for(std::vector<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->something();
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->second->something();
}

for(auto it = x.begin(); it != x.end(); it++ )
{
   it->??
}

Sembra che se non sai se hai un iteratore per una mappa o un vettore non sapresti se usare firsto secondo semplicemente accedere direttamente alle proprietà dell'oggetto, no?

Questo mi ricorda il dibattito in C # sull'uso della parola chiave var. L'impressione che sto ottenendo finora è che nel mondo C ++ le persone sono pronte ad adottare la autoparola chiave con meno combattimenti rispetto varal mondo C #. Per me il mio primo istinto è che mi piace conoscere il tipo di variabile in modo da poter sapere quali operazioni posso aspettarmi di eseguire su di essa.


3
Aspettare! C'è stata una discussione sull'opportunità di usare var? Ho perso questo.
pdr,

21
Ancora meglio, puoi semplicemente usare for (auto& it : x) (o senza riferimento se vuoi copiare)
Tamás Szelei,

7
Mi sembra che tu stia scrivendo un loop per scorrere i contenuti di xe non sai nemmeno cosa xsia, non dovresti scrivere quel loop in primo luogo ;-)
nikie

@fish: regole basate su range for-loops, ma sarei stato pedante e fatto: 'for (T & it: x)' invece quando usassi il for-loop basato su range, dato che penso che usare auto ci sia meno informativo. Una specie di uso improprio dell'auto nella mia mente.
martiert,

La lotta per l'uso di var è stata un po 'sciocca, specialmente a posteriori. Vedi la programmazione di culto Cargo .
Craig

Risposte:


38

Le motivazioni in C ++ sono più estreme, poiché i tipi possono diventare molto più contorti e complessi rispetto ai tipi C # a causa della metaprogrammazione e di altre cose. autoè più veloce da scrivere e leggere e più flessibile / gestibile di un tipo esplicito. Voglio dire, vuoi iniziare a digitare

boost::multi_map<NodeType, indexed_by<ordered_unique<identity<NodeType>>, hashed_non_unique<identity<NodeType>, custom_hasher>>::iterator_type<0> it

Questo non è nemmeno il tipo completo. Ho perso un paio di argomenti sui template.


8
+1 per l'esempio, ma questo dice anche qualcosa sullo stato del C ++ "moderno".
zvrba,

22
@zvrba: Sì, le strutture generiche sono molto più potenti di quelle di C #.
DeadMG

4
ecco a cosa serve typedef
gbjbaanb,

19
@gbjbaanb No, questo è ciò che autoserve. Di progettazione. typedefaiuta, ma autoaiuta di più.
Konrad Rudolph,

1
typedef invalida l'argomento secondo cui "il non utilizzo di auto fa per tipi molto lunghi"
Michael

28

Nel tuo esempio:

for(auto it = x.begin(); it != x.end(); i++)
{
  it->??
}

ci deve essere una dichiarazione per xvisibile. Pertanto, il tipo di itdovrebbe essere ovvio. Se il tipo di xnon è ovvio, il metodo è troppo lungo o la classe è troppo grande.


7
Inoltre, xè un nome variabile molto brutto per un contenitore. In alcune situazioni, molto probabilmente puoi semplicemente guardare il nome (semanticamente prezioso) e dedurre le possibili operazioni.
Max

@Max: usato solo xcome esempio generico, tendo ad usare nomi di variabili abbastanza descrittivi.
Utente

@Utente Certo, non pensavo che fosse un esempio del mondo reale;)
Max

14

Obiezione ! Domanda caricata.

Puoi spiegarmi perché il terzo codice contiene ??, ma il primo e il secondo no? Per onestà, il tuo codice deve essere il seguente:

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->???
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->second->???
}

Là. Stesso problema anche se non l'hai usatoauto .

E in tutti i casi, la risposta è la stessa: il contesto è importante . Non puoi parlare in modo significativo di un pezzo di codice in isolamento. Anche se non avessi usato modelli ma qualche tipo concreto, questo avrebbe spostato il problema solo altrove, dal momento che il lettore del tuo codice avrebbe dovuto conoscere la dichiarazione di quel tipo.

Se l'uso di auto queste situazioni rende il tuo codice illeggibile, dovresti considerare questo come un segnale di avvertimento che c'è qualcosa di sbagliato nella progettazione del tuo codice. Naturalmente, ci sono casi in cui contano dettagli di basso livello (come quando si tratta di operazioni con bit o API legacy) in cui un tipo esplicito potrebbe aiutare la leggibilità. Ma in generale - no.

Per quanto riguarda var(dal momento che l'hai menzionato esplicitamente), esiste anche un ampio consenso nella comunità C # per l' utilizzo var. Gli argomenti contro il suo uso sono generalmente basati su errori .


1
Penso che il punto fosse, con auto non sai cosa mettere dopo ... è il tuo codice specifico "qualcosa" o è un tipo di dato relativo al disimballaggio per arrivare al tuo oggetto dati che ha il metodo "qualcosa"
Michael Shaw,

1
@Ptolemy E il mio punto è: negli altri due codici anche tu non sai (in generale) cosa mettere dopo: Tè opaco per l'utente quanto auto. Eppure uno dovrebbe andare bene e l'altro no ?! Non ha senso. Nel caso di OP, Tè uno stand-in per un tipo arbitrario. Nel codice reale, può essere l'uso di modelli (for typename std::vector<T>::iterator…)o un'interfaccia di classe. In entrambi i casi, il tipo effettivo è nascosto all'utente e tuttavia scriviamo regolarmente tale codice senza problemi.
Konrad Rudolph,

1
In realtà sì. Se è un vettore, sai che devi fare -> e quindi hai accesso al tuo tipo di dati. Se è una mappa, sai che devi fare -> secondo-> e quindi hai accesso al tuo tipo di dati, se è automatico, non sai cosa devi fare per ottenere l'accesso al tuo tipo di dati. Sembri confondere il "qual è il tipo di dati contenuto nella raccolta STL" con "quale tipo di raccolta STL abbiamo". auto peggiora questo problema.
Michael Shaw,

1
@Ptolemy Tutti questi argomenti sono altrettanto veri quando si usa auto. È banale vedere quali operazioni xsupportano dal contesto. In realtà, il tipo che si dà alcuna informazione supplementare: in entrambi i casi avete bisogno di qualche secondario (IDE, la documentazione, la conoscenza / memoria) a dire la serie di operazioni supportate.
Konrad Rudolph,

1
@Ptolemy Questo è solo vero se si è in una situazione molto contorto che non si sa cosa begini rendimenti ma non sa che cosa std::vector<>::iteratorsia. E devi usare un cattivo strumento di programmazione che non può darti banalmente queste informazioni. Questo è altamente contorto. In realtà, si sia conoscere sia begine iteratoro nessuno, e si dovrebbe utilizzare un IDE o un editor che può facilmente rendere le informazioni pertinenti a vostra disposizione. Ogni IDE ed editor di programmazione moderno può farlo.
Konrad Rudolph,

11

PRO

Il tuo codice :

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

non verrà compilato, a causa del nome dipendente dal modello.

Questa è la sintassi corretta:

for( typename std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

Ora guarda quanto è lunga la dichiarazione del tipo. Questo spiega perché è autostata introdotta la parola chiave. Questo :

for( auto it = x.begin(); it != x.end(); i++)

è più conciso. Quindi, questo è un professionista.


CON

Devi stare un po 'attento. Con la parola chiave auto, ottieni il tipo che hai dichiarato.

Per esempio :

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto it : v )
{
  ++ it;   // ops modifying copies of vector's elements
}

vs

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto & it : v )   // mind the reference
{
  ++ it;   // ok, vector's elements modified
}

Per concludere: sì, dovresti, ma non abusarne. Alcune persone tendono a usarlo troppo e mettono auto ovunque, come nel prossimo esempio:

auto i = 0;

vs

int i = 0;

auto i = 0. Colpevole. Lo faccio. Ma è perché so che 0è un tipo letterale int. (e una costante ottale ;-))
Laurent LA RIZZA,

6

Si, dovresti! autonon cancella il tipo; anche se "non sai" cos'è x.begin(), il compilatore lo sa e segnalerà un errore se provi a usare il tipo in modo errato. Inoltre, non è insolito emulare mapcon a vector<pair<Key,Value>>, quindi il codice utilizzato autofunzionerà per entrambe le rappresentazioni del dizionario.


4

Sì, è necessario utilizzare autocome regola predefinita. Presenta vantaggi evidenti rispetto alla specifica esplicita del tipo:

  • Non ti fa scrivere cose di cui il compilatore è già a conoscenza.
  • Fa sì che il tipo di variabili "segua" qualsiasi modifica nei tipi di valore restituiti.
  • In questo modo, impedisce l' introduzione silenziosa di conversioni implicite e lo slicing nell'inizializzazione delle variabili locali.
  • Elimina la necessità di alcuni calcoli di tipo esplicito nei modelli.
  • Elimina la necessità di denominare i tipi restituiti con nomi lunghi. (quelli che copia e incolla dalla diagnostica del compilatore)

Questo è dove hai una scelta. Ci sono anche casi in cui non hai scelta:

  • Permette la dichiarazione di variabili di tipo indicibile, come il tipo di lambda.

A condizione che tu sappia esattamente cosa autofa, non ha svantaggi.

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.