Wie wechsle ich zu C ++ 11?

35

Ich programmiere jetzt schon eine Weile in C ++, aber die meisten Dinge drehten sich um die Low-Level-Funktionen von C ++. Damit meine ich hauptsächlich die Arbeit mit Zeigern und unformatierten Arrays. Ich denke, dieses Verhalten ist als C ++ als C mit Klassen bekannt. Trotzdem habe ich C erst kürzlich zum ersten Mal ausprobiert. Ich war angenehm überrascht, wie Sprachen wie C # und Java diese Details in praktischen Standardbibliotheksklassen wie Wörterbüchern und Listen verbergen.

Mir ist bewusst, dass die C ++ - Standardbibliothek auch viele Container wie Vektoren, Maps und Strings enthält und C ++ 11 dies nur durch std :: array- und ranged-Schleifen ergänzt.

Wie lerne ich am besten, diese modernen Sprachfunktionen zu nutzen und welche eignen sich für welche Momente? Ist es richtig, dass das Software-Engineering in C ++ heutzutage weitgehend frei von manueller Speicherverwaltung ist?

Welchen Compiler soll ich verwenden, um den neuen Standard optimal zu nutzen? Visual Studio verfügt über hervorragende Debugging-Tools, aber selbst VS2012 scheint eine schreckliche C ++ 11-Unterstützung zu haben.

Overv
quelle
2
Ich würde sagen, dass es etwas übertrieben ist, die C ++ 11-Unterstützung von VS2012 als "schrecklich" zu bezeichnen, aber es könnte sicherlich besser sein (fehlende Initialisierungslisten sind besonders ärgerlich für Test- / Spielzeugcode). Beachten Sie jedoch, dass sie angekündigt haben, Compiler-Updates unabhängig vom Rest von VS zu veröffentlichen. Ich denke, wir können im Laufe des Jahres 2013 auf eine ganze Reihe von C ++ 11-Features in VS2012 hoffen.
Martin Ba,
3
Zuerst dachte ich, es für das Erlernen von C ++ 11 vorzuschlagen, wäre seltsam, aber zu sehen, dass Sie immer noch im C-With-Classes- Land stecken ... Vor einem Jahrzehnt las ich Koenig / Moos Accelerated C ++ . Zu dem Zeitpunkt, als ich bereits Template-Meta-Programmierung durchführte (ich habe es nur zur Überprüfung gelesen), fühlte es sich dennoch wie eine Offenbarung an. (Ich habe es seitdem als Basis für das Unterrichten von C ++ verwendet.) Aus C kommend zeigt Ihnen das Buch eine ganz neue Sprache, von der Sie nicht wussten, dass Sie sie zur Verfügung hatten. Es sind nur 250 Seiten, und Sie können dann schnell zu etwas C ++ 11-spezifischem übergehen, aber IMO ist es ein lohnender Schritt.
sbi
4
g++ -std=c++11
Fredoverflow

Antworten:

50

Zunächst einige Faustregeln:

  • Verwendung std::unique_ptrals intelligenter No-Overhead-Zeiger. Sie sollten sich nicht allzu oft mit rohen Zeigern herumschlagen müssen. std::shared_ptrist in den meisten Fällen ebenfalls unnötig. Der Wunsch nach gemeinsamem Eigentum verrät oftmals, dass man überhaupt nicht an Eigentum denkt.

  • Verwendung std::arrayfür Arrays mit statischer Länge und std::vectorfür dynamische Arrays .

  • Verwenden Sie generische Algorithmen in großem Umfang, insbesondere:

    • <algorithm>
    • <numeric>
    • <iterator>
    • <functional>
  • Verwendung autound decltype()wo immer sie der Lesbarkeit zugute kommen. Insbesondere, wenn Sie eine Sache deklarieren möchten, aber einen Typ, den Sie nicht interessieren, wie z. B. einen Iterator oder einen komplexen Vorlagentyp, verwenden Sie auto. Wenn Sie eine Sache in Bezug auf die Art einer anderen Sache deklarieren möchten, verwenden Sie decltype().

  • Machen Sie Dinge typsicher, wenn Sie können. Wenn Sie Behauptungen haben, die Invarianten für eine bestimmte Sache erzwingen, kann diese Logik in einem Typ zentralisiert werden. Dies bedeutet nicht unbedingt einen zusätzlichen Aufwand für die Laufzeit. Es sollte auch selbstverständlich sein, dass C-Casts ( (T)x) sollen mich für die explizit C ++ zu vermeiden (und durchsuchbar!) - Casts (zB static_cast).

  • Schließlich wissen, wie die Regel von drei:

    • Zerstörer
    • Konstruktor kopieren
    • Aufgabenverwalter

    Wurde die Regel von fünf mit der Hinzufügung des Verschiebungskonstruktors und des Verschiebungszuweisungsoperators. Und verstehen Sie rvalue-Referenzen im Allgemeinen und wie Sie das Kopieren vermeiden.

C ++ ist eine komplexe Sprache, so dass es schwierig ist , zu charakterisieren , wie am besten nutzen alle davon. Aber die Praktiken einer guten C ++ - Entwicklung haben sich mit C ++ 11 nicht grundlegend geändert. Sie sollten weiterhin speicherverwaltete Container der manuellen Speicherverwaltung vorziehen. Intelligente Zeiger erleichtern dies auf effiziente Weise.

Ich würde sagen, dass modernes C ++ tatsächlich größtenteils frei von manueller Speicherverwaltung ist. Der Vorteil des C ++ - Speichermodells besteht darin, dass es deterministisch und nicht manuell ist. Vorhersehbare Aufhebungen sorgen für eine vorhersehbarere Leistung.

Was einen Compiler angeht, so sind sowohl G ++ als auch Clang in Bezug auf C ++ 11-Funktionen wettbewerbsfähig und können ihre Mängel rasch beheben. Ich benutze kein Visual Studio, daher kann ich weder dafür noch dagegen sprechen.

Zum Schluss noch ein Hinweis zu std::for_each: Vermeiden Sie es generell.

transform, accumulateUnd erase- remove_ifsind gute alte funktionale map, foldund filter. Ist for_eachaber allgemeiner und daher weniger aussagekräftig - es drückt keine andere Absicht als Schleifen aus. Außerdem wird es in den gleichen Situationen wie bereichsbasiert verwendet forund ist syntaktisch schwerer, selbst wenn es ohne Punkte verwendet wird. Erwägen:

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);
Jon Purdy
quelle
6
Gibt es einige verbindliche Grundsätze für diese Faustregeln? Es scheint eine schöne Liste von Vorschlägen zu sein, aber ... Wie hilft mir Ihre Antwort, als Außenseiter, der über Google zu dieser Frage gelangt, C ++ 11 auf prinzipielle Weise zu lernen und es zu verwenden, ohne mich um die C ++ - Achse zu wickeln? ?
Robert Harvey
3
+1 für die Liste, aber ich habe einen kleinen Trottel: Wenn std::for_eachich (zu Recht) davor gewarnt hätte, hätte ich erwartet, dass der Bereich basierend auf der for-Schleife ein besserer Ersatz ist als normal for.
Fabio Fracassi
@ FabioFracassi: Ups. Ich habe klar und deutlich geschrieben std::for_each, nicht bereichsbezogen . Ich habe es entfernt, um Verwirrung zu vermeiden.
Jon Purdy
1
Ich würde aktualisieren, wenn es nicht wäre std::for_each(). Wenn Sie Lambda haben, ist es sicherlich besser als eine traditionelle forSchleife. Bei einer bereichsbasierten forSchleife ist dies möglicherweise nicht der Fall, aber Sie haben keine "bereichsbasierte forSchleife" geschrieben.
sbi
@sbi: Meiner Meinung nach umfasst der Begriff " forSchleife" " bereichsbasierte forSchleife". Ich habe mit mehr Erklärung und einem Beispiel zur Verdeutlichung bearbeitet, danke.
Jon Purdy
12

Als Ausgangspunkt:

  • Stoppen Sie die Verwendung char*für Zeichenfolgen. Verwenden Sie std::stringoder std::wstringund beobachten Sie, wie Ihr Code kürzer, lesbarer und sicherer wird
  • Stoppen Sie die Verwendung von Arrays im C-Stil (Dinge, die mit deklariert wurden [ ]) und verwenden Sie std::vectoroder eine andere geeignete Containerklasse. Das Schöne daran std::vectorist, dass es seine eigene Länge kennt, seinen Inhalt aufräumt, wenn es den Rahmen verlässt, leicht wiederholt werden kann und sich vergrößert, wenn Sie weitere Elemente hinzufügen. Es gibt jedoch auch andere Sammlungen, die unter Ihren Umständen möglicherweise noch besser funktionieren.
  • Verwenden std::unique_ptr- und std::movefast sofort lernen . Da dies in einigen noncopyable Objekte führen, Faulheit kann man gelegentlich senden std::shared_ptr- und Sie können für einige echte Anwendungsfälle haben std::shared_ptrauch
  • Verwenden Sie, autowenn Iteratoren und Arten zu erklären , die auf früheren Erklärungen abhängen (zB früher Sie einen Vektor von etwas erklärt, jetzt bist du ein etwas zu erklären, verwenden auto)
  • Verwenden Sie Algorithmen und for_eachüber ein "raw for", wann immer Sie können, da dies andere daran hindert, Ihre Schleife sorgfältig zu lesen, um daraus zu schließen, dass Sie tatsächlich die gesamte Sammlung usw. durchlaufen. Wenn Ihr Compiler "range for" unterstützt, verwenden Sie es über for_each. Erfahren triviale Algorithmus Anrufe wie iota, generate, accumulate, find_ifund so weiter.
  • Verwenden Sie Lambdas - sie sind der einfache Weg, Algorithmen zu nutzen. Sie öffnen auch die Tür zu so viel mehr.

Überlegen Sie nicht, welchen Compiler Sie verwenden sollen. Der "schreckliche, schreckliche" Mangel an C ++ 11-Unterstützung in VS2012 besteht darin, dass es keine variablen Vorlagen gibt (ja, richtig, Sie wollten gerade variable Vorlagen verwenden) und der {}Initialisierer nicht vorhanden ist. Ich möchte das auch, aber ich werde kaum aufhören, ein nützliches Entwicklungstool dafür zu verwenden.

Das zweite, was Sie nach der Umarmung tun müssen std::, ist, an RAII zu denken. Immer wenn du hast

  • Aktion starten
  • Reihe von Aktionen mit etwas, das Sie von Beginn an Aktion bekam
  • Bereinigungsaktion, die auch in Ausnahmefällen ausgeführt werden muss

Dann haben Sie einen Konstruktor, eine Reihe von Elementfunktionen und einen Destruktor. Schreiben Sie eine Klasse, die das für Sie erledigt. Möglicherweise müssen Sie nicht einmal den ctor und den dtor schreiben. Das Einfügen einer shared_ptrVariablen als Mitglied einer Klasse ist ein Beispiel für RAII - Sie schreiben keinen Speicherverwaltungscode, aber wenn Ihre Instanz den Gültigkeitsbereich verlässt, werden die richtigen Dinge passieren. Erweitern Sie dieses Denken, um Dinge wie das Schließen von Dateien, das Freigeben von Handles, Sperren usw. und Code zu behandeln. Dies wird vor Ihren Augen einfacher und kleiner (und beseitigt Lecks).

Wenn Sie sich wirklich sicher fühlen, Spülung printffür cout, erhalten von Makros (rid #defineSachen) und beginnen , einige „fortgeschrittenen Idiome“ wie PIMPL lernen. Ich habe einen ganzen Kurs dazu bei Pluralsight, den Sie wahrscheinlich mit ihrer kostenlosen Testversion ansehen können.

Kate Gregory
quelle
2
Ich mag, wie sarkastisch Sie sind, wenn er nicht bald verschiedene Vorlagen verwendet, aber ich denke, dass eine fehlende einheitliche Initialisierung etwas wirklich Wichtiges für die tägliche Programmierung vermisst.
sbi
Ich kann es kaum erwarten, Initialisiererlisten zu erhalten ... ich warte darauf, herauszufinden, wann wir sie erhalten ...
Kate Gregory
Ein weiterer wichtiger Mangel in VS2012 sind "rvalue references v3", dh der automatisch generierte Verschiebungskonstruktor und die Verschiebungszuweisung.
Mr.C64
3

Wie lerne ich am besten, diese modernen Sprachfunktionen zu nutzen und welche eignen sich für welche Momente?

Durch Programmierung. Erfahrung ist der beste Weg, um zu lernen.

C ++ 11 hat viele neue Funktionen (Auto, R-Wert, neue intelligente Zeiger - um nur einige zu nennen). Der beste Anfang ist, sie einfach zu verwenden und zu lesen, wann immer Sie können und wann immer Sie einen interessanten Artikel finden.

Ist es richtig, dass das Software-Engineering in C ++ heutzutage weitgehend frei von manueller Speicherverwaltung ist?

Das hängt davon ab, was Sie tun müssen. Die meisten Anwendungen können mit intelligenten Zeigern davonkommen und die Speicherverwaltung vergessen. Es gibt immer noch Anwendungen, die nicht so einfach davonkommen können (z. B. wenn sie neu platziert werden müssen oder einen benutzerdefinierten Speicherzuweiser, aus welchem ​​Grund auch immer).

Wenn Sie Qt verwenden müssen, müssen Sie deren Regeln für die Speicherverwaltung verwenden.

Welchen Compiler soll ich verwenden, um den neuen Standard optimal zu nutzen?

Was auch immer Sie zur Hand haben, das den neuesten Standard unterstützt:

aber kein Compiler unterstützt alle Funktionen.

BЈовић
quelle
-7

Meine Universität verwendet immer noch C ++ für den Unterricht. Ich habe 5 Jahre lang mit C ++ programmiert und bin jetzt ein Doktorand. Natürlich benutze ich jetzt viel Java, Ruby usw. Ich empfehle wirklich, dass Sie sich nicht zu sehr mit diesen Funktionen in einer Sprache wie Java beeilen. Nach meiner Erfahrung und Meinung nach nach den Low-Level-Funktionen von C ++. Sie sollten sich mit Themen wie der generischen Programmierung mit C / C ++ wie dem Erstellen von Vorlagenklassen, Vorlagenfunktionen, dem Überschreiben von Operatoren, virtuellen Methoden und intelligenten Zeigern befassen. Für den objektorientierten Entwurf gibt es viele Funktionen, die C ++ bietet, und Java nicht, wie beispielsweise die Mehrfachvererbung. Vererbung ist mächtig, aber auch gefährlich. Die Implementierungsebene des objektorientierten Designs in C ++ ist ebenfalls ein gutes Thema. Prozessübergreifende Kommunikation, Threadings, sind auch in C ++ wichtig.

Für den Compiler und Debugger. Ich weiß, dass Visual Studio großartig ist. Aber ich empfehle Ihnen wirklich, GDB, Valgrind und Make still zu lernen und diese Tools gut zu beherrschen. Microsoft ist großartig, aber es hat zu viele Dinge für Sie getan. Als Student müssen Sie wirklich die Dinge lernen, die Microsoft auch für Sie getan hat. Für den Compiler ist G ++ von GNU gut.

Nach so vielen Jahren denke ich, sind die wichtigsten Dinge die Low-Level-Features wie Raw Array. Vector ist eigentlich nur ein dynamisches Array. Dies sind meine Empfehlungen, vielleicht etwas zu subjektiv. Nehmen Sie einfach, was Sie für richtig halten.

Sen Han
quelle
6
Wie beantwortet dies die Frage? Die Frage ist nicht das Erlernen von C ++ im Allgemeinen, sondern das Wechseln zu C ++ 11.
Roc Martí