Come passare a C ++ 11?

35

Ho programmato in C ++ per un po 'di tempo, ma per lo più le cose erano incentrate sulle funzionalità di basso livello del C ++. Con ciò intendo principalmente il lavoro con i puntatori e gli array grezzi. Penso che questo comportamento sia noto come usare C ++ come C con le classi. Nonostante questo, ho provato solo C di recente per la prima volta. Sono rimasto piacevolmente sorpreso dal fatto che linguaggi come C # e Java nascondano questi dettagli in comode classi di librerie standard come Dizionari ed Elenchi.

Sono consapevole che la libreria standard C ++ ha molti contenitori come i vettori, le mappe e le stringhe e C ++ 11 si limita a questo aggiungendo std :: array e loop a ranghi.

Come faccio a imparare meglio a utilizzare queste caratteristiche linguistiche moderne e quali sono adatti a quali momenti? È corretto che l'ingegneria del software in C ++ oggigiorno sia per lo più priva di gestione manuale della memoria?

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

    
posta Overv 23.10.2012 - 00:37
fonte

4 risposte

50

Innanzitutto, alcune regole pratiche:

  • Usa std::unique_ptr come puntatore intelligente senza overhead. Non dovresti aver bisogno di preoccuparti dei puntatori grezzi tutto questo spesso. std::shared_ptr è ugualmente inutile nella maggior parte dei casi. Un desiderio di proprietà condivisa spesso tradisce una mancanza di pensiero sulla proprietà in primo luogo.

  • Utilizza std::array per array di lunghezza statica e std::vector per dinamico.

  • Utilizza estensivamente algoritmi generici, in particolare:

    • <algorithm>
    • <numeric>
    • <iterator>
    • <functional>
  • Utilizza auto e decltype() ovunque siano a vantaggio della 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 al tipo quando puoi. Quando si hanno asserzioni che impongono invarianti su un particolare tipo di cosa, tale logica può essere centralizzata in un tipo. E questo non fa necessariamente per qualsiasi 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 esempio static_cast ).

  • Infine, conosci la regola del tre:

    • Destructor
    • Copia costruttore
    • Operatore di assegnazione

    È diventata la regola del cinque con l'aggiunta del costruttore di movimento e dell'operatore di spostamento. E capire i riferimenti rvalue in generale e come evitare di copiare.

C ++ è un linguaggio complesso, quindi è difficile caratterizzare il modo migliore per utilizzare tutti di esso. Ma le pratiche di un buon sviluppo del C ++ non sono cambiate fondamentalmente con C ++ 11. Dovresti comunque preferire i contenitori gestiti tramite memoria rispetto alla gestione manuale della memoria: i puntatori intelligenti semplificano l'esecuzione in modo efficiente.

Direi che il C ++ moderno è per lo più privo di gestione manuale della memoria: il vantaggio del modello di memoria di C ++ è che è deterministico , non che sia manuale. Le deallocazioni prevedibili offrono prestazioni più prevedibili.

Come per un compilatore, G ++ e Clang sono entrambi competitivi in termini di funzionalità di C ++ 11 e recuperano rapidamente le loro carenze. Non utilizzo Visual Studio, quindi non posso parlare né a favore né contro di esso.

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

transform , accumulate e erase - remove_if sono buoni vecchi funzionali map , fold e filter . Ma for_each è più generale, e quindi meno significativo: non esprime alcun intento diverso dal ciclo. Oltre a ciò, viene utilizzato nelle stesse situazioni di for basato su intervallo ed è sintatticamente più pesante, anche se utilizzato senza punto. Prendere in considerazione:

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);
    
risposta data 23.10.2012 - 00:50
fonte
12

Come punto di partenza:

  • Interrompi l'utilizzo di char* per le stringhe. Usa std::string o std::wstring e guarda il tuo codice diventare più breve, più leggibile e più sicuro
  • Smetti di usare matrici in stile C (cose dichiarate con [ ] ) e usa std::vector o qualche altra classe contenitore appropriata. Le cose belle su std::vector sono che conosce la sua lunghezza, ripulisce il suo contenuto quando esce dal campo di applicazione, è facile da iterare e diventa più grande quando aggiungi più elementi. Ma ci sono altre raccolte che potrebbero funzionare ancora meglio per le tue circostanze.
  • Utilizza std::unique_ptr - e impara quasi immediatamente std::move . Poiché questo potrebbe causare alcuni oggetti non copiabili, la pigrizia potrebbe occasionalmente inviarti verso std::shared_ptr - e potresti anche avere alcuni casi d'uso genuini per std::shared_ptr
  • Utilizza auto quando si dichiarano iteratori e tipi che dipendono da dichiarazioni precedenti (ad esempio, in precedenza hai dichiarato un vettore di qualcosa, ora stai dichiarando qualcosa, usa auto )
  • Usa gli algoritmi e for_each su un "raw for" ogni volta che puoi, dal momento che risparmia agli altri di leggere attentamente il tuo ciclo per concludere che stai di fatto iterando sull'intera collezione ecc. Se il tuo compilatore supporta "range for" quindi usalo su for_each . Impara chiamate algoritmiche banali come iota , generate , accumulate , find_if e così via.
  • Usa lambdas: sono il modo più semplice per sfruttare gli algoritmi. Aprono anche la porta a molto di più.

Non ti preoccupare troppo di quale compilatore usare. La "terribile, orribile" mancanza di supporto C ++ 11 in VS2012 è che non ci sono modelli variadici (sì giusto, eri solo circa per usare modelli variadici) e l'inizializzatore {} non è Là. Lo voglio anche io ma non riuscirò più a usare uno strumento di sviluppo utile su di esso.

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

  • azione iniziale
  • serie di azioni con qualcosa che hai ottenuto iniziando l'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 classe che si prende cura di quello per te. Potresti anche non dover scrivere il ctor e il dtor. Inserire un shared_ptr come variabile membro di una classe è un esempio di RAII: non si scrive codice di gestione della memoria, ma quando l'istanza esce dall'ambito, accadranno le cose giuste. Espandi il tuo pensiero per coprire aspetti come la chiusura di file, il rilascio di maniglie, serrature ecc. E il codice diventerà più semplice e più piccolo (eliminando le perdite) davanti ai tuoi occhi.

Se ti senti veramente sicuro, elimina printf a favore di cout , elimina le macro ( #define roba) e inizia a imparare alcuni "idiomi avanzati" come PIMPL. Ho un corso completo su questo a Pluralsight che probabilmente puoi guardare utilizzando la versione di prova gratuita.

    
risposta data 23.10.2012 - 13:13
fonte
3

How do I best learn to make use of these modern language features and which are suitable for which moments?

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

C ++ 11 ha molte nuove funzionalità (auto, rvalue, nuovi puntatori intelligenti - solo per citarne alcuni). L'inizio migliore è iniziare a usarli e leggere su di loro ogni volta che puoi e ogni volta che trovi un articolo interessante.

Is it correct that software engineering in C++ nowadays is mostly free of manual memory management?

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

Se hai bisogno di usare Qt, dovrai usare le loro regole per la gestione della memoria.

which compiler should I use to make the most of the new standard?

Qualunque cosa tu abbia a disposizione che supporti l'ultimo standard:

ma nessun compilatore supporta tutte le funzionalità.

    
risposta data 23.10.2012 - 12:42
fonte
-7

La mia università usa ancora il C ++ per insegnare. Ho programmato con C ++ per 5 anni e ora sono uno studente laureato. Certo, ora sto usando molto Java, Ruby, ecc. Vi raccomando caldamente di non avere troppa fretta su quelle funzionalità in linguaggio come Java. Nella mia esperienza e opinione, dopo le caratteristiche di basso livello del C ++. Dovresti esaminare argomenti come la programmazione generica con C / C ++ come fare classi template, funzioni template, overritten dell'operatore, metodi virtuali, puntatori intelligenti. Per la parte di progettazione orientata agli oggetti, ci sono molte funzionalità in C + + e Java no, come la multi-eredità. L'ereditarietà è potente ma anche pericolosa. Anche il livello di implementazione della progettazione orientata agli oggetti in C ++ è un buon argomento. Anche la comunicazione tra processi, i threading sono importanti in C ++.

Per il compilatore e il debugger. So che lo studio visivo è fantastico. Ma io consiglio vivamente di imparare GDB, Valgrind e Make still, e di essere bravo con questi strumenti. Microsoft è fantastica, ma ha fatto troppe cose per te. Da studente, hai davvero bisogno di imparare quelle cose che anche Microsoft ti ha fatto. Per il compilatore, G ++ è buono da GNU.

Dopo tutto, dopo tanti anni, mi sento davvero, le cose più importanti sono le funzionalità di basso livello come array raw. Il vettore è in realtà solo un array dinamico. Queste sono le mie raccomandazioni, qualcosa forse troppo soggettivo, prendi semplicemente ciò che pensi sia giusto.

    
risposta data 23.10.2012 - 03:25
fonte

Leggi altre domande sui tag