Code-Review in C++: Was prüfen und wie man Feedback gibt
\n\nCode-Review ist einer der wichtigsten Schritte in der Softwareentwicklung. Besonders wichtig ist dies für C++, wo Fehler bei der Speicherverwaltung oder die falsche Verwendung der Standardbibliothek zu ernsthaften Problemen führen können. In diesem Artikel besprechen wir, worauf man bei der Überprüfung von C++-Code achten sollte und wie man Feedback gibt, das hilfreich und nicht verletzend ist.
\n\nWarum ist Code-Review für C++ wichtig?
\n\nC++ ist eine leistungsstarke, aber komplexe Sprache. Sie gibt dem Entwickler ein hohes Maß an Kontrolle, erfordert aber auch Sorgfalt. Typische Probleme: Speicherlecks, undefiniertes Verhalten, ineffiziente Algorithmen. Ein gutes Code-Review hilft, solche Fehler zu erkennen, bevor sie in die Produktion gelangen.
\n\nFür Anfänger ist Code-Review nicht nur eine Prüfung, sondern auch eine Lernmöglichkeit. Durch Feedback lernt man, qualitativ hochwertigeren Code zu schreiben. Durch das Durchführen von Reviews lernt man zu analysieren und zu argumentieren.
\n\nWas in C++-Code prüfen: Checkliste
\n\nUm das Review systematisch zu gestalten, verwenden Sie die folgende Checkliste.
\n\n1. Speicher- und Ressourcenverwaltung
\n\nDies ist die Grundlage von C++. Fehler hier sind am gefährlichsten.
\n- \n
- Werden intelligente Zeiger anstelle von rohen Zeigern verwendet?
std::unique_ptrundstd::shared_ptrsollten Standard sein. Rohe Zeiger sind nur zur Beobachtung (non-owning) zulässig. \n - Gibt es Speicherlecks? Überprüfen Sie, ob jedes
newein entsprechendesdeletehat (falls keine intelligenten Zeiger verwendet werden). \n - Werden Ressourcen korrekt freigegeben? Dateien, Sockets, Mutexe sollten in RAII-Klassen gekapselt sein. \n
// Schlecht: roher Zeiger und manuelle Verwaltung\nvoid process() {\n int* data = new int[100];\n // ... wenn hier eine Ausnahme auftritt, gibt es ein Leck\n delete[] data;\n}\n\n// Gut: intelligenter Zeiger\nvoid process() {\n auto data = std::make_unique<int[]>(100);\n // Speicher wird automatisch freigegeben\n}\n\n2. Typsicherheit und Vermeidung von undefiniertem Verhalten
\n\nC++ ist voller undefiniertem Verhalten (UB). Der Reviewer muss wachsam sein.
\n- \n
- Gibt es einen Zugriff außerhalb der Array-Grenzen? Verwenden Sie
std::arrayoderstd::vectormit.at()anstelle von rohen Arrays. \n - Ist die Typumwandlung korrekt? Vermeiden Sie C-Style-Casts. Verwenden Sie bewusst
static_cast,dynamic_cast,const_castoderreinterpret_cast. \n - Sind alle Variablen initialisiert? Nicht initialisierte Variablen sind eine häufige Ursache für UB. \n
- Gibt es einen Überlauf von vorzeichenbehafteten Ganzzahlen? In C++ ist dies UB. \n
// Schlecht: C-Style-Cast und nicht initialisierte Variable\nint* p = (int*)malloc(sizeof(int));\nint x; // nicht initialisiert\n*p = x; // UB\n\n// Gut: explizite Umwandlung und Initialisierung\nint* p = static_cast<int*>(std::malloc(sizeof(int)));\nint x = 0;\n*p = x;\n\n3. Leistung und Effizienz
\n\nMan muss nicht immer nach Geschwindigkeit streben, aber offensichtliche Engpässe sollten behoben werden.
\n- \n
- Werden Objekte unnötig per Wert übergeben? Große Objekte sollten per konstanter Referenz (
const &) übergeben werden. \n - Gibt es unnötige Kopien? Verwenden Sie Move-Semantik, wo es angebracht ist. \n
- Ist der Container richtig gewählt?
std::vectorfür schnellen Indexzugriff,std::listfür häufige Einfügungen in der Mitte. \n - Wird eine virtuelle Funktion in einer heißen Schleife aufgerufen? Dies kann langsam sein. \n
// Langsam: Kopieren eines großen Objekts\nvoid process(std::string s) { /* ... */ }\n\n// Schnell: Übergabe per konstanter Referenz\nvoid process(c