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 und std::vector
für dynamische Arrays .
Verwenden Sie generische Algorithmen in großem Umfang, insbesondere:
<algorithm>
<numeric>
<iterator>
<functional>
Verwendung auto
und 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
, accumulate
Und erase
- remove_if
sind gute alte funktionale map
, fold
und filter
. Ist for_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 verwendet for
und 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);