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.
g++ -std=c++11
Antworten:
Zunächst einige Faustregeln:
Verwendung
std::unique_ptr
als intelligenter No-Overhead-Zeiger. Sie sollten sich nicht allzu oft mit rohen Zeigern herumschlagen müssen.std::shared_ptr
ist 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::array
für Arrays mit statischer Länge undstd::vector
für dynamische Arrays .Verwenden Sie generische Algorithmen in großem Umfang, insbesondere:
<algorithm>
<numeric>
<iterator>
<functional>
Verwendung
auto
unddecltype()
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 Sieauto
. Wenn Sie eine Sache in Bezug auf die Art einer anderen Sache deklarieren möchten, verwenden Siedecltype()
.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 (zBstatic_cast
).Schließlich wissen, wie die Regel von drei:
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
,accumulate
Underase
-remove_if
sind gute alte funktionalemap
,fold
undfilter
. Istfor_each
aber 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 verwendetfor
und ist syntaktisch schwerer, selbst wenn es ohne Punkte verwendet wird. Erwägen:quelle
std::for_each
ich (zu Recht) davor gewarnt hätte, hätte ich erwartet, dass der Bereich basierend auf der for-Schleife ein besserer Ersatz ist als normalfor
.std::for_each
, nicht bereichsbezogen . Ich habe es entfernt, um Verwirrung zu vermeiden.std::for_each()
. Wenn Sie Lambda haben, ist es sicherlich besser als eine traditionellefor
Schleife. Bei einer bereichsbasiertenfor
Schleife ist dies möglicherweise nicht der Fall, aber Sie haben keine "bereichsbasiertefor
Schleife" geschrieben.for
Schleife" " bereichsbasiertefor
Schleife". Ich habe mit mehr Erklärung und einem Beispiel zur Verdeutlichung bearbeitet, danke.Als Ausgangspunkt:
char*
für Zeichenfolgen. Verwenden Siestd::string
oderstd::wstring
und beobachten Sie, wie Ihr Code kürzer, lesbarer und sicherer wird[ ]
) und verwenden Siestd::vector
oder eine andere geeignete Containerklasse. Das Schöne daranstd::vector
ist, 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.std::unique_ptr
- undstd::move
fast sofort lernen . Da dies in einigen noncopyable Objekte führen, Faulheit kann man gelegentlich sendenstd::shared_ptr
- und Sie können für einige echte Anwendungsfälle habenstd::shared_ptr
auchauto
wenn 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, verwendenauto
)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 überfor_each
. Erfahren triviale Algorithmus Anrufe wieiota
,generate
,accumulate
,find_if
und so weiter.Ü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 hastDann 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_ptr
Variablen 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
printf
fürcout
, erhalten von Makros (rid#define
Sachen) 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.quelle
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.
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.
Was auch immer Sie zur Hand haben, das den neuesten Standard unterstützt:
aber kein Compiler unterstützt alle Funktionen.
quelle
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.
quelle