Come passare a C ++ 11?


35

Sto programmando in C ++ da un po 'di tempo, ma principalmente le cose si sono concentrate sulle funzionalità di basso livello di C ++. Con questo intendo principalmente lavorare con puntatori e array grezzi. Penso che questo comportamento sia noto come l'uso di C ++ come C con le classi. Nonostante ciò, ho provato C solo di recente per la prima volta. Sono stato piacevolmente sorpreso dal fatto che linguaggi come C # e Java nascondano questi dettagli in comode classi di biblioteche standard come dizionari ed elenchi.

Sono consapevole che la libreria standard C ++ ha molti contenitori come vettori, mappe e stringhe e C ++ 11 aggiunge solo a ciò avendo std :: array e loop a distanza.

Come posso imparare ad usare al meglio queste funzionalità linguistiche moderne e quali sono adatte a quali momenti? È corretto che l'ingegneria del software in C ++ al giorno d'oggi sia per lo più priva della gestione manuale della memoria?

Infine, quale compilatore dovrei usare per sfruttare al meglio il nuovo standard? Visual Studio ha eccellenti strumenti di debug, ma anche VS2012 sembra avere un terribile supporto C ++ 11.


2
Direi che chiamare il supporto di C ++ 11 di VS2012 "terribile" è un po 'esagerato, ma sicuramente potrebbe essere migliore (perdere gli elenchi di inizializzatori è particolarmente fastidioso per il codice test / giocattolo). Ma nota che hanno annunciato che pubblicheranno aggiornamenti del compilatore indipendentemente dal resto di VS, quindi immagino che possiamo sperare in un bel po 'di funzionalità C ++ 11 in VS2012 nel corso del 2013.
Martin Ba,

3
All'inizio ho pensato che suggerirlo per l'apprendimento del C ++ 11 sarebbe strano, ma visto che sei ancora bloccato nella terra delle classi C ... Con un decennio fa ho letto il C ++ accelerato di Koenig / Moo . Quando stavo già realizzando la meta-programmazione dei template (l'ho letto solo per una recensione), ma mi sembrava ancora una rivelazione. (Da allora l'ho usato come base per insegnare il C ++.) Venendo dalla C Con Classes , il libro può mostrarti una lingua completamente nuova che non sapevi di avere a tua disposizione. Sono solo 250 pagine e puoi passare rapidamente a qualcosa di specifico per C ++ 11, ma IMO è un passo utile.
sbi,

4
g++ -std=c++11
fredoverflow,

Risposte:


50

Innanzitutto, alcune regole pratiche:

  • Utilizzare std::unique_ptrcome puntatore intelligente senza spese generali. Non dovresti preoccuparti di puntatori non elaborati molto spesso. std::shared_ptrè anche inutile nella maggior parte dei casi. Un desiderio di proprietà condivisa spesso tradisce in primo luogo una mancanza di pensiero sulla proprietà.

  • Utilizzare std::arrayper matrici di lunghezza statica e std::vectordinamica.

  • Utilizzare ampiamente algoritmi generici, in particolare:

    • <algorithm>
    • <numeric>
    • <iterator>
    • <functional>
  • Utilizzare autoe decltype()ovunque giovano alla leggibilità. In particolare, quando vuoi dichiarare una cosa, ma di un tipo che non ti interessa come un iteratore o un tipo di modello complesso, usa auto. Quando vuoi dichiarare una cosa in termini di tipo di un'altra cosa, usa decltype().

  • Rendi le cose sicure quando puoi. Quando hai affermazioni che impongono gli invarianti su un particolare tipo di cosa, quella logica può essere centralizzata in un tipo. E questo non comporta necessariamente alcun sovraccarico di runtime. Va anche detto che i cast in stile C ( (T)x) dovrebbero essere evitati a favore dei cast più espliciti (e ricercabili!) In stile C ++ (ad es static_cast.).

  • Infine, sapere come la regola di tre:

    • Distruttore
    • Copia costruttore
    • Operatore di assegnazione

    È diventata la regola del cinque con l'aggiunta del costruttore di spostamenti e dell'operatore di assegnazione di spostamenti. Comprendi i riferimenti ai valori in generale e come evitare la copia.

C ++ è un linguaggio complesso, quindi è difficile da caratterizzare il modo migliore per utilizzare tutto di esso. Ma le pratiche del buon sviluppo del C ++ non sono cambiate sostanzialmente con il C ++ 11. Dovresti comunque preferire i contenitori gestiti dalla memoria rispetto alla gestione manuale della memoria: i puntatori intelligenti consentono di farlo in modo efficiente.

Direi che il moderno C ++ è in effetti per lo più privo di gestione manuale della memoria: il vantaggio del modello di memoria del C ++ è che è deterministico , non manuale. Deallocations prevedibili rendono le prestazioni più prevedibili.

Per quanto riguarda un compilatore, G ++ e Clang sono entrambi competitivi in ​​termini di funzionalità C ++ 11 e stanno rapidamente recuperando le loro carenze. Non uso Visual Studio, quindi non posso parlare né a favore né contro.

Infine, una nota su std::for_each: evitarlo in generale.

transform, accumulateE erase- remove_ifsono il buon vecchio funzionali map, folde filter. Ma for_eachè più generale e quindi meno significativo: non esprime alcun intento diverso dal looping. Oltre a ciò, viene utilizzato nelle stesse situazioni di range-based fored è sintatticamente più pesante, anche se usato senza punti. Ritenere:

for (const auto i : container)
    std::cout << i << '\n';

std::for_each(container.begin(), container.end(), [](int i) {
    std::cout << i << '\n';
});

for (const auto i : container)
    frobnicate(i);

std::for_each(container.begin(), container.end(), frobnicate);

6
Esistono principi vincolanti per queste regole empiriche? Sembra un bel elenco di suggerimenti, ma ... Come outsider che arriva a questa domanda tramite Google, in che modo la tua risposta mi aiuta a raccogliere C ++ 11 in modo di principio e usarlo senza avvolgermi attorno all'asse C ++ ?
Robert Harvey,

3
+1 per l'elenco, ma ho un piccolo nitpick: quando (giustamente) un avvertimento contro std::for_eachmi sarei aspettato che l'intervallo basato su loop fosse un rimpiazzo migliore del semplice for.
Fabio Fracassi,

@FabioFracassi: Oops. Ho scritto chiaramente in contrasto con std::for_each, non con range-based . L'ho rimosso per evitare confusione.
Jon Purdy

1
Vorrei aggiornare se non fosse per std::for_each(). Quando hai lambda, è sicuramente meglio di un forciclo tradizionale . Con un forciclo basato su intervallo che potrebbe non essere il caso, ma non hai scritto " forciclo basato su intervallo ".
sbi,

@sbi: Nella mia mente, il termine " forloop" include " forloop basato sul range ". Ho modificato con più spiegazioni e un esempio per chiarire, grazie.
Jon Purdy,

12

Come punto di partenza:

  • Smetti di usare char*per le stringhe. Usa std::stringo std::wstringe solo guarda il tuo codice diventare più breve, più leggibile e più sicuro
  • Smetti di usare le matrici in stile C (cose dichiarate con [ ]) e usa std::vectoro qualche altra classe contenitore appropriata. La cosa bella std::vectorè che conosce la sua lunghezza, pulisce i suoi contenuti quando esce dal campo di applicazione, è facile da scorrere e diventa più grande quando aggiungi più elementi. Ma ci sono altre collezioni che potrebbero funzionare ancora meglio per le tue circostanze.
  • Uso std::unique_ptr - e impara std::movequasi immediatamente. Dal momento che questo potrebbe causare alcuni oggetti noncopyable, la pigrizia può occasionalmente inviare verso std::shared_ptr- e si può avere alcuni casi d'uso originali per std::shared_ptroltre
  • Utilizzare autoquando si dichiarano iteratori e tipi che dipendono da dichiarazioni precedenti (ad es. In precedenza si è dichiarato un vettore di qualcosa, ora si sta dichiarando qualcosa, utilizzare auto)
  • Usa gli algoritmi e for_eacholtre un "raw per" ogni volta che puoi poiché risparmia gli altri dalla lettura del tuo ciclo con attenzione per concludere che stai effettivamente iterando su tutta la raccolta ecc. Se il tuo compilatore supporta "range for", usalo sopra for_each. Per saperne di chiamate algoritmo banali come iota, generate,accumulate , find_ife così via.
  • Usa lambda: sono il modo semplice per sfruttare gli algoritmi. Aprono anche la porta a molto di più.

Non preoccuparti troppo di quale compilatore utilizzare. Il "terribile terribile," mancanza di C ++ 11 supporto in VS2012 è che non c'è modelli variadic (yeah a destra, eri quasi per utilizzare i modelli variadic) e l' {}inizializzatore non c'è. Lo voglio anch'io ma difficilmente smetterò di utilizzare un utile strumento di sviluppo su di esso.

La seconda cosa da fare, dopo aver abbracciato std::, è iniziare a pensare alla RAII. Ogni volta che hai

  • azione iniziale
  • serie di azioni con qualcosa che hai ottenuto dall'avvio dell'azione
  • azione di pulizia che deve avvenire anche in caso di eccezioni

Quindi quello che hai è un costruttore, un numero di funzioni membro e un distruttore. Scrivi una lezione che si prende cura di questo per te. Potrebbe non essere nemmeno necessario scrivere il ctor e il dtor. Mettere ashared_ptr variabile come membro di una classe è un esempio di RAII: non si scrive il codice di gestione della memoria, ma quando l'istanza esce dal campo di applicazione, accadranno le cose giuste. Espandi questo pensiero per coprire cose come la chiusura di file, il rilascio di handle, blocchi ecc. E il codice diventerà sempre più semplice e più piccolo (eliminando le perdite) davanti ai tuoi occhi.

Se ti senti davvero fiducioso, elimina printfin favore cout, elimina le macro ( #definecose) e inizia a imparare alcuni "modi di dire avanzati" come PIMPL. A Pluralsight ho un intero corso che probabilmente puoi guardare usando la loro prova gratuita.


2
Mi piace come sei sarcastico sul fatto che non utilizzi modelli variadici in qualunque momento presto, ma penso che mancando un'inizializzazione uniforme manchi qualcosa di veramente importante per la programmazione quotidiana.
sbi,

Non vedo l'ora per gli elenchi di inizializzatori ... in attesa di scoprire quando li avremo ...
Kate Gregory,

Un'altra importante mancanza in VS2012 sono i "riferimenti di valore v3", ovvero il costruttore di movimenti generato automaticamente e l'assegnazione di movimenti.
Mr.C64,

3

Come posso imparare ad usare al meglio queste funzionalità linguistiche moderne e quali sono adatte a quali momenti?

Programmando. L'esperienza è il modo migliore per imparare.

C ++ 11 ha molte nuove funzionalità (auto, rvalue, nuovi puntatori intelligenti - solo per citarne alcuni). Il miglior inizio è iniziare a usarli e leggerli ogni volta che puoi e ogni volta che trovi un articolo interessante.

È corretto che l'ingegneria del software in C ++ al giorno d'oggi sia per lo più priva della gestione manuale della memoria?

Dipende da cosa devi fare. La maggior parte delle applicazioni può cavarsela con puntatori intelligenti e dimenticare la gestione della memoria. Esistono ancora applicazioni che non riescono a cavarsela così facilmente (ad esempio se hanno bisogno di un posizionamento nuovo o di un allocatore di memoria personalizzato per qualsiasi motivo).

Se devi usare Qt, dovrai usare le loro regole per la gestione della memoria.

quale compilatore dovrei usare per sfruttare al meglio il nuovo standard?

Qualunque cosa tu abbia a portata di mano che supporti gli ultimi standard:

ma nessun compilatore supporta tutte le funzionalità.


-7

La mia università sta ancora usando C ++ per insegnare. Ho programmato con C ++ per 5 anni e ora sono uno studente laureato. Certo, ora sto usando molto Java, Ruby ecc. Consiglio vivamente di non affrettarti troppo su quelle funzionalità in un linguaggio come Java. Secondo la mia esperienza e opinione, dopo le funzionalità di basso livello di C ++. Dovresti esaminare argomenti come la programmazione generica con C / C ++ come creare classe di modello, funzioni di modello, sovrascritto operatore, metodi virtuali, puntatori intelligenti. Per la parte di progettazione orientata agli oggetti, ci sono molte funzionalità di C ++ e Java no, come l'ereditarietà multipla. L'ereditarietà è potente ma anche pericolosa. Anche il livello di implementazione della progettazione orientata agli oggetti in C ++ è un buon argomento. La comunicazione tra processi, i thread, sono importanti anche in C ++.

Per il compilatore e il debugger. So che Visual Studio è fantastico. Ma ti consiglio davvero di imparare GDB, Valgrind e Make still, e di essere bravo con questi strumenti. Microsoft è fantastica, ma ha fatto troppe cose per te. Come studente, devi davvero imparare quelle cose che anche Microsoft ha fatto. Per il compilatore, G ++ è buono da GNU.

Dopotutto, dopo tanti anni, mi sento davvero, le cose più importanti sono le funzionalità di basso livello come l'array raw. Il vettore è davvero solo un array dinamico. Questi sono i miei consigli, qualcosa di forse troppo soggettivo, prendi quello che pensi sia giusto.


6
Come risponde alla domanda? La domanda non riguarda l'apprendimento del C ++ in generale, ma il passaggio al C ++ 11.
Roc Martí,
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.