Schlechteste Praktiken in C ++, häufige Fehler [geschlossen]


35

Nachdem ich diese berühmte Parole von Linus Torvalds gelesen hatte , fragte ich mich, was eigentlich die Tücken für Programmierer in C ++ sind. Ich beziehe mich ausdrücklich nicht auf Tippfehler oder fehlerhafte Programmabläufe, wie sie in dieser Frage und ihren Antworten behandelt werden , sondern auf übergeordnete Fehler, die vom Compiler nicht erkannt werden und keine offensichtlichen Fehler beim ersten Start verursachen, vollständige Entwurfsfehler. Dinge, die in C unwahrscheinlich sind, aber wahrscheinlich in C ++ von Neulingen erledigt werden, die die vollständigen Auswirkungen ihres Codes nicht verstehen.

Ich begrüße auch Antworten, die auf einen enormen Leistungsabfall hinweisen, der normalerweise nicht zu erwarten ist. Ein Beispiel dafür, was mir einer meiner Professoren einmal über einen LR (1) -Parsergenerator erzählt hat:

Sie haben etwas zu viele Instanzen nicht benötigter Vererbung und Virtualität verwendet. Vererbung erschwert einen Entwurf erheblich (und ist aufgrund des RTTI-Subsystems (Runtime Type Inference) ineffizient) und sollte daher nur dort verwendet werden, wo dies sinnvoll ist, z. B. für die Aktionen in der Analysetabelle. Da Sie Vorlagen intensiv nutzen, benötigen Sie praktisch keine Vererbung. "


6
Einige der schlimmeren Fehler, die Sie in C / C ++ machen können, sind hauptsächlich auf das C-Erbe zurückzuführen ein C ++ - Experte) - Template-Instanziierung sollte eine normale Klasse mit vtable for virtualfunctions ergeben, oder?

8
Entweder erinnern Sie sich falsch an das, was Ihr Professor gesagt hat, oder er hatte keine Ahnung, wovon er sprach. Abgeleitete Klassen müssen im Allgemeinen nicht RTTI (AKA Reflection) verwenden, um nachzuschlagen. Wenn sie virtuelle Methoden verwenden, muss der Code möglicherweise eine vtable-Suche für den Versand durchführen, was sich jedoch in einer einzelnen ASM-Anweisung auf vielen Prozessoren niederschlägt. Aufgrund von Caching-Problemen kann dies zu einer gewissen Verlangsamung führen, es ist jedoch unwahrscheinlich, dass Sie den Overhead in den anspruchsvollsten Anwendungsfällen jemals bemerken. Es gibt viele gute Gründe, C ++ zu vermeiden, aber Vtable-Lookups gehören nicht dazu.
Mason Wheeler

5
@FelixDombek: So allgemein formuliert und allgemein angewendet, zeigt dieses Zitat Ihres Professors nur eine Menge Ignoranz. Wenn für Ihr Design eine Art Laufzeitpolymorphismus erforderlich ist , ist die Verwendung virtueller Funktionen häufig die beste Wahl. Wenn Sie es nicht benötigen, verwenden Sie es nicht: Es müssen nicht alle Methoden virtuell sein, nur weil Sie beispielsweise abgeleitete Klassen verwenden.
Fred Nurk

5
@Mason Wheeler: RTTI enthält Informationen zum Typ, die ausreichen, um zu bestimmen, ob eine erfolgreich sein dynamic_castsoll oder nicht, und einige andere Dinge, aber die Reflexion deckt noch viel mehr ab, einschließlich der Möglichkeit, Informationen zu Mitgliedsattributen oder -funktionen abzurufen, die nicht erfolgreich sind in C ++ vorhanden.
David Rodríguez - dribeas

5
Der Kommentar des Professors täuscht etwas, da Vererbung und virtuelle Funktionen keine großen Leistungseinbußen darstellen. Der Rat, Vererbung sparsam zu verwenden, ist gut, aber es ist eher ein Problem der Programmstruktur als der Effizienz. Vererbung, insbesondere bei geschützten Mitgliedern, ist eine so enge Verbindung wie möglich. Wenn Sie sie nicht benötigen, sollten Sie sie nicht verwenden.
David Thornley

Antworten:


69

Torvalds redet hier aus seinem Arsch.


OK, warum redet er aus seinem Arsch:

Zuallererst ist sein Schimpfen wirklich nichts, ABER Schimpfen. Hier gibt es sehr wenig aktuellen Inhalt. Der einzige Grund, warum es wirklich berühmt oder sogar geachtet ist, ist, dass es vom Linux-Gott gemacht wurde. Sein Hauptargument ist, dass C ++ Mist ist und er es mag, C ++ Leute wütend zu machen. Es gibt natürlich überhaupt keinen Grund, darauf zu antworten, und jeder, der dies für ein vernünftiges Argument hält, ist sowieso nicht zu diskutieren.

Was als seine objektivsten Punkte angesehen werden könnte:

  • STL und Boost sind völliger Blödsinn. Du bist ein Idiot.
  • STL und Boost verursachen unendlich viele Schmerzen <- lächerlich. Offensichtlich übertreibt er absichtlich, aber was ist dann seine wahre Aussage hier? Ich weiß es nicht. Es ist mehr als trivial schwierig, Probleme herauszufinden, wenn Sie Compiler-Erbrochenes in Spirit oder so verursachen, aber es ist nicht mehr oder weniger schwierig herauszufinden, als das Debuggen von UB, das durch den Missbrauch von C-Konstrukten wie void * verursacht wird.
  • Abstrakte Modelle, die von C ++ unterstützt werden, sind ineffizient. <- Wie was? Er dehnt sich niemals aus, liefert niemals Beispiele für das, was er meint, er sagt es nur. BFD. Da ich nicht sagen kann, worauf er sich bezieht, hat es wenig Sinn, zu versuchen, die Aussage zu "widerlegen". Es ist ein weit verbreitetes Mantra von C-Bigots, aber das macht es nicht verständlicher oder verständlicher.
  • Die korrekte Verwendung von C ++ bedeutet, dass Sie sich auf die C-Aspekte beschränken. <- Eigentlich macht das der WORSE C ++ - Code da draußen, also weiß ich immer noch nicht, über WTF er spricht.

Grundsätzlich redet Torvalds aus seinem Arsch. Es gibt keine verständlichen Argumente für irgendetwas. Eine ernsthafte Widerlegung eines solchen Unsinns zu erwarten, ist einfach albern. Mir wird gesagt, ich solle eine Widerlegung von etwas "erweitern", von dem ich erwarten würde, dass es erweitert wird, wenn ich es dort finde, wo ich es gesagt habe. Wenn Sie sich ehrlich ansehen, was Torvalds gesagt hat, werden Sie feststellen, dass er eigentlich nichts gesagt hat.

Nur weil Gott sagt, dass es nicht bedeutet, dass es irgendeinen Sinn macht oder ernst genommen werden sollte, als wenn irgendein zufälliger Bozo es gesagt hätte. Um ehrlich zu sein, Gott ist nur ein weiterer Zufallsbozo.


Auf die eigentliche Frage antworten:

Die wahrscheinlich schlimmste und häufigste schlechte C ++ - Praxis besteht darin, sie wie C zu behandeln. Die fortgesetzte Verwendung von C-API-Funktionen wie printf, gets (gilt auch in C als schlecht), strtok usw. kann die bereitgestellte Leistung nicht nur nicht nutzen Durch das engere Typensystem führen sie unweigerlich zu weiteren Komplikationen, wenn versucht wird, mit "echtem" C ++ - Code zu interagieren. Machen Sie also genau das Gegenteil von dem, was Torvalds empfiehlt.

Erfahren Sie, wie Sie STL und Boost nutzen, um Fehler beim Kompilieren schneller zu erkennen und Ihr Leben auf andere, allgemeine Weise zu vereinfachen (der Boost-Tokenizer ist beispielsweise sowohl typensicher als auch eine bessere Benutzeroberfläche). Es ist wahr, dass Sie lernen müssen, wie man Template-Fehler liest, was zunächst einschüchternd ist, aber (meiner Erfahrung nach) ist es ehrlich gesagt viel einfacher, etwas zu debuggen, das während der Laufzeit undefiniertes Verhalten erzeugt, das die C-API erzeugt ganz einfach zu machen.

Um nicht zu sagen, dass C nicht so gut ist. Ich mag C ++ natürlich besser. C-Programmierer mögen C besser. Es gibt Kompromisse und subjektive Vorlieben. Es gibt auch viele Fehlinformationen und FUD. Ich würde sagen, dass es mehr FUD und Fehlinformationen über C ++ gibt, aber in dieser Hinsicht bin ich voreingenommen. Zum Beispiel sind die Probleme "Aufblähen" und "Leistung", die C ++ angeblich hat, die meiste Zeit keine größeren Probleme und werden mit Sicherheit aus den Proportionen der Realität gerissen.

Die Probleme, auf die sich Ihr Professor bezieht, sind nicht nur in C ++ zu finden. In OOP (und in der generischen Programmierung) möchten Sie die Komposition der Vererbung vorziehen. Vererbung ist die stärkste mögliche Kopplungsbeziehung, die in allen OO-Sprachen besteht. C ++ fügt eine weitere hinzu, die stärker ist, Freundschaft. Polymorphe Vererbung sollte verwendet werden, um Abstraktionen und "Ist-Eine" -Beziehungen darzustellen. Sie sollte niemals zur Wiederverwendung verwendet werden. Dies ist der zweitgrößte Fehler, den Sie in C ++ machen können, und es ist ein ziemlich großer Fehler, der jedoch für die Sprache alles andere als eindeutig ist. Sie können auch in C # oder Java übermäßig komplexe Vererbungsbeziehungen erstellen, bei denen genau dieselben Probleme auftreten.


1
Ironischerweise lief git bis weit nach 2007 nur mit portablen Versionen von Linux. Nun, jedes System, das Unix-ähnlich war. Andererseits halte ich es angesichts der Umstände, die zur Entstehung von GIT geführt haben, nicht gegen ihn.
Chris K

9
Es fällt Linus schwer, gute C ++ - Programmierer zu finden, die für ihn arbeiten wollen. Fragen, warum? Ich denke, das ist nur ein Henne-Ei-Problem.
Bo Persson

19

Ich habe immer gedacht, dass die Gefahren von C ++ von unerfahrenen C-Klassen-Programmierern stark übertrieben wurden.

Ja, C ++ ist schwieriger zu erlernen als Java, aber wenn Sie mit modernen Techniken programmieren, ist es ziemlich einfach, robuste Programme zu schreiben. Ehrlich gesagt , ich habe nicht , dass viele schwieriger eine Zeitprogrammierung in C ++ als ich in Sprachen wie Java zu tun, und ich finde ich oft bestimmen C ++ Abstraktionen wie Vorlagen und RAII fehlen , wenn ich in anderen Sprachen entwerfen.

Das heißt, auch nach Jahren des Programmierens in C ++ mache ich hin und wieder einen wirklich dummen Fehler, der in einer höheren Sprache nicht möglich wäre. Eine häufige Gefahr in C ++ ist das Ignorieren der Objektlebensdauer: In Java und C # müssen Sie sich im Allgemeinen nicht um die Objektlebensdauer * kümmern, da alle Objekte auf dem Heap vorhanden sind und von einem magischen Garbage Collector für Sie verwaltet werden.

Nun, in der modernen C ++, in der Regel brauchen Sie nicht viel über das Objekt Lebenszeit entweder zu kümmern. Sie haben Destruktoren und intelligente Zeiger, die die Lebensdauer von Objekten für Sie verwalten. In 99% der Fälle funktioniert dies wunderbar. Aber hin und wieder werden Sie von einem baumelnden Zeiger (oder einer Referenz) verarscht. Zum Beispiel hatte ich kürzlich ein Objekt (nennen wir es Foo), das eine interne Referenzvariable zu einem anderen Objekt enthielt (nennen wir es Bar). Irgendwann habe ich dummerweise Dinge so arrangiert, dass Barsie vorher Foonicht mehr in Frage kamen , und doch hat Fooder Destruktor eine Member - Funktion von aufgerufen Bar. Natürlich lief es nicht gut.

Nun, ich kann C ++ nicht wirklich dafür verantwortlich machen. Es war mein eigenes schlechtes Design, aber der Punkt ist, dass so etwas in einer übergeordneten, verwalteten Sprache nicht passieren würde. Selbst mit intelligenten Zeigern und Ähnlichem müssen Sie sich manchmal der Objektlebensdauer bewusst sein.


* Wenn es sich bei der verwalteten Ressource um Speicher handelt, ist dies der Fall.


8
Müssen Sie sich nie wirklich um die Objektlebensdauer in Java und C # kümmern? Ihr GC kümmert sich um das Gedächtnis, aber das ist für mich nur ein kleiner Teil von RAII; Schauen Sie sich zum Beispiel die verschiedenen "Einweg" -Oberflächen an, die diese Sprachen haben.
Fred Nurk

Die Objektlebensdauer berücksichtigen zu müssen, ist in Java selten, mit Ausnahme des unpraktischen Designs der E / A-Bibliothek.
dan04

Ich bin daran interessiert, Ihr schwebendes Referenzproblem zu lösen. Ich habe in meinem Blog eine Diskussion darüber begonnen, in welche Richtung ich es lösen möchte (Zeiger verspricht). Grundsätzlich denke ich, dass die Sprache ein paar klügere Zeiger gebrauchen könnte. Nehmen Sie an dieser Diskussion teil, wenn Sie interessiert sind. Niemand anderes war so ... aber wenn es etwas ist, das Sie gerne gelöst sehen würden ... bin ich in der Tat viel mehr als 10% der Fälle auf das Problem gestoßen.
Edward Strange

13

Der Unterschied im Code hängt normalerweise mehr mit dem Programmierer als mit der Sprache zusammen. Insbesondere ein guter C ++ - Programmierer und ein C-Programmierer kommen beide zu ähnlich guten (auch wenn unterschiedlichen) Lösungen. Jetzt ist C eine einfachere Sprache (als Sprache) und das bedeutet, dass es weniger Abstraktionen gibt und mehr Einblick in das, was der Code tatsächlich tut.

Ein Teil seines Rants (er ist bekannt für seine Rants gegen C ++) basiert auf der Tatsache, dass mehr Leute sich mit C ++ auseinandersetzen und Code schreiben, ohne wirklich zu verstehen, was einige der Abstraktionen verbergen und falsche Annahmen treffen.


3
Was kostet es, einen std::vector<bool>Wert zu ändern? for ( std::vector<bool>::iterator it = v.begin(), end = v.end(); it != end; ++it ) { *it = !*it; }? Was ist in abstrahiert *it = !*it;?
David Rodríguez - dribeas

2
Obwohl es unfair sein kann, auf bestimmte
Sprachabscheulichkeiten zu stoßen, die

2
@Fred Nurk: std::vector<bool>ist ein bekannter Fehler, aber es ist ein wirklich gutes Beispiel dafür, was diskutiert wird: Abstraktionen sind gut, aber man muss aufpassen, was sie verbergen. Das gleiche kann und wird im Benutzercode passieren. Für den Anfang habe ich gesehen, dass sowohl in C ++ als auch in Java Ausnahmen verwendet werden, um die Ablaufsteuerung durchzuführen, und Code, der wie ein Aufruf einer Verschachtelungsfunktion aussieht, der eigentlich ein Ausnahmebefehlsprogramm für Rettungsaktionen ist: void endOperation();implementiert als throw EndOperation;. Ein guter Programmierer wird diese überraschenden Konstrukte vermeiden , aber Tatsache ist, dass Sie sie finden können.
David Rodríguez - dribeas

5
Einer der Punkte von Torvalds ist, dass er Anfänger einfach durch die Wahl von C gegenüber C ++ vertreiben kann (es scheint mehr C ++ - Anfänger zu geben) und dass C ++ komplexer ist, eine steilere Lernkurve hat und dass es in einem Eckfall mehr Chancen gibt, zu stolpern .
David Rodríguez - dribeas

2
+1, genau darüber beklagt sich Linus. Er ist Anti-C ++, aber das ist nicht wirklich so. Er ist nur Anti-C ++ - Programmierer.
greyfade

13

Überbeanspruchung von try/catchBlöcken.

File file("some.txt");
try
{
  /**/

  file.close();
}
catch(std::exception const& e)
{
  file.close();
}

Dies ist normalerweise auf Sprachen wie Java zurückzuführen, und die Leute werden argumentieren, dass C ++ eine finalizeKlausel fehlt .

Dieser Code weist jedoch zwei Probleme auf:

  • Man muss filevor dem bauen try/catch, weil man eigentlich closekeine Datei kann, in der es keine gibt catch. Dies führt zu einem "Zielfernrohrleck", filedas nach dem Schließen sichtbar wird. Sie können einen Block hinzufügen, aber ...: /
  • Wenn jemand vorbeikommt und returnmitten im tryGültigkeitsbereich eine hinzufügt , wird die Datei nicht geschlossen (weshalb die Leute sich über das Fehlen einer finalizeKlausel beschweren).

In C ++ haben wir jedoch wesentlich effizientere Möglichkeiten, mit diesem Problem umzugehen:

  • Java's finalize
  • C # 's using
  • Los geht's defer

Wir haben RAII, dessen wirklich interessante Eigenschaft sich am besten als SBRM(Scoped Bound Resources Management) zusammenfassen lässt.

Indem wir die Klasse so gestalten, dass ihr Destruktor die Ressourcen bereinigt, die sie besitzt, müssen wir nicht jeden einzelnen Benutzer mit der Verwaltung der Ressourcen beauftragen!

Dies ist die Funktion, die ich in jeder anderen Sprache vermisse und wahrscheinlich die, die am meisten vergessen wird.

Die Wahrheit ist, dass es selten nötig ist, einen try/catchBlock in C ++ zu schreiben , abgesehen von der obersten Ebene, um eine Beendigung ohne Protokollierung zu vermeiden.


1
Ich denke nicht, dass es der Einfluss von Java ist, wie es C ist. (Sie könnten direkt fopenund fclosehier ersetzen .) RAII ist die "richtige" Art, Dinge hier zu tun, aber es ist unpraktisch für Leute, die C-Bibliotheken aus C ++ verwenden möchten .
dan04

Für diese Art der Antwort wäre es angemessen, ein Beispiel für die richtige Lösung anzugeben.
Claus Jørgensen

@ ClausJørgensen: Naja, die Lösung ist leider nicht wirklich "auffällig", da es nur darum geht File file("some.txt");und das ist es (nein open, nein close, nein try...)
Matthieu M.

D hat auch RAII
Demi

@ Demetri: Ich bin nicht sehr vertraut mit D, können Sie erklären, wie RAII mit Garbage Collection interagiert? Ich weiß, dass Sie in Python eine "Deinit" -Methode schreiben können. In der Dokumentation wird jedoch gewarnt, dass einige Objekte im Falle eines Referenzzyklus nicht sehen, wie ihre Deinit-Methode aufgerufen wird.
Matthieu M.

9

Ein häufiger Fehler, der Ihren Kriterien entspricht, besteht darin, nicht zu verstehen, wie Kopierkonstruktoren im Umgang mit dem zugewiesenen Speicher in Ihrer Klasse funktionieren. Ich habe die Anzahl der Zeit, die ich damit verbracht habe, Abstürze oder Speicherlecks zu beheben, verloren, weil ein 'Noob' seine Objekte in eine Karte oder einen Vektor gesteckt hat und Kopierkonstruktoren und Destruktoren nicht richtig geschrieben hat.

Leider steckt C ++ voller "versteckter" Fallstricke. Aber sich darüber zu beschweren ist wie sich zu beschweren, dass du nach Frankreich gegangen bist und nicht verstehen konntest, was die Leute sagten. Wenn Sie dorthin gehen, lernen Sie die Sprache.


1
Ich denke, das Problem mit C ++ ist, dass es sehr einfach ist, sich in den Fuß zu schießen. Klar, es gibt gute C ++ - Programmierer, viele gute in C ++ geschriebene Software. Aber es ist sehr schwierig, ein guter C ++ - Entwickler zu werden. Scott Meyers 'Efficient C ++' Serie zeigt, wie viele Feinheiten die Sprache hat.
Marco Mustapic

Genau. Ein Teil des Problems ist jedoch, dass viele (die Mehrheit) der C ++ - Programmierer glauben, zu wissen, was sie tun, wenn sie dies eindeutig nicht tun. Meinten Sie "Effective C ++"?
Henry

Zumindest wird dies mit den neuen, eher restriktiven Regeln für die implizite Generierung von Kopier- / Verschiebevorgängen in C ++ 0x immer besser. In vielen Fällen, in denen die Dreierregel verletzt wird, wird die implizite Generierung von Kopiervorgängen veraltet sein und eine Warnung auslösen.
Sellibitze

6

C ++ ermöglicht eine Vielzahl von Funktionen und Programmierstilen. Dies bedeutet jedoch nicht, dass dies eine gute Möglichkeit für die Verwendung von C ++ ist. Tatsächlich ist es unglaublich einfach, C ++ falsch zu verwenden.

Es muss richtig erlernt und verstanden werden . Nur das Erlernen durch Ausführen (oder die Verwendung wie eine andere Sprache) führt zu ineffizientem und fehleranfälligem Code.


4

Nun ... Für den Anfang können Sie die lesen C ++ FAQ Lite

Dann haben mehrere Leute Karrieren aufgebaut und Bücher über die Feinheiten von C ++ geschrieben:

Herb Sutter und Scott Meyers nämlich.

Was die mangelnde Substanz von Torvalds angeht ... nehmen Sie es ernst: In keiner anderen Sprache wurde so viel Tinte auf den Umgang mit den Nuancen der Sprache verschüttet. Ihre Python & Ruby & Java-Bücher konzentrieren sich alle auf das Schreiben von Anwendungen ... Ihre C ++ - Bücher konzentrieren sich auf alberne Sprachfunktionen / Tipps / Traps.


1
Hmm ... javapuzzlers.com , jimbrooks.org/web/python/#Pitfalls . Ich würde sagen, Accelerated C ++ (zum Beispiel) konzentriert sich viel mehr auf das Schreiben von Code als diese ...
Jerry Coffin

1
Sie haben einige Beispiele für Ressourcen aufgeführt, die Randfälle in der jeweiligen Sprache aufzeigen. Dinge , die seltsam aussehen und du bist nicht ganz sicher , wie sie (obwohl die Python - Liste Sachen in der Nähe) arbeiten würden ... C ++ haben eine ganze Industrie Dinge , die den Hinweis auf aussehen vollkommen gültig , dass verhalten in einer Weise , Sie nicht erwarten.
Red-Dirt

3

Zu starkes Templating führt möglicherweise zunächst nicht zu Fehlern. Mit der Zeit müssen die Benutzer diesen Code jedoch ändern, und es fällt ihnen schwer, eine riesige Vorlage zu verstehen. In diesem Moment treten Fehler auf - Missverständnisse führen dazu, dass Kommentare "kompiliert und ausgeführt werden", die häufig zu einem fast, aber nicht ganz korrekten Code führen.

Wenn ich mir vorstelle, wie ich eine dreistufige, tiefe generische Vorlage mache, höre ich auf und überlege, wie ich sie auf eine reduzieren könnte. Oft wird das Problem durch Extrahieren von Funktionen oder Klassen gelöst.


8
Das Beibehalten von kompliziertem Code angesichts sich ändernder Anforderungen führt immer ohne großen Aufwand zu Fehlern, nichts Besonderes an Vorlagen.
Fred Nurk

2

Warnung: Dies ist bei weitem keine so gute Antwort wie eine Kritik an dem Vortrag, auf den "Benutzer unbekannt" in seiner Antwort verwiesen hat.

Sein erster Hauptpunkt ist der (angeblich) "sich ständig ändernde Standard". In Wirklichkeit beziehen sich die Beispiele, die er nennt, alle auf Änderungen in C ++, bevor es einen Standard gab. Seit 1998 (als der erste C ++ - Standard fertiggestellt wurde) waren die Änderungen an der Sprache recht gering - tatsächlich würden viele argumentieren, dass das eigentliche Problem darin besteht, dass weitere Änderungen hätten vorgenommen werden müssen. Ich bin mir ziemlich sicher, dass der gesamte Code, der dem ursprünglichen C ++ - Standard entspricht, weiterhin dem aktuellen Standard entspricht. Es wird zwar etwas weniger sicher, aber es sei denn, etwas ändert sich schnell (und ganz unerwartet), dasselbe gilt auch für den kommenden C ++ - Standard (theoretisch für den gesamten verwendeten Code)export kaputt gehen, aber es gibt praktisch keine. aus praktischer Sicht ist es kein Problem). Ich kann mir nur wenige andere Sprachen, Betriebssysteme (oder vieles andere im Zusammenhang mit Computern) vorstellen, die einen solchen Anspruch erheben können.

Er geht dann in "ständig wechselnde Stile". Auch hier liegen die meisten seiner Punkte ziemlich nahe am Unsinn. Er versucht, for (int i=0; i<n;i++)als "alt und kaputt" und for (int i(0); i!=n;++i)"neue Schärfe" zu charakterisieren . Die Realität ist, dass es zwar Typen gibt, für die solche Änderungen sinnvoll sein könnten int, es aber keinen Unterschied macht - und selbst wenn Sie etwas gewinnen könnten, ist es selten notwendig, guten oder korrekten Code zu schreiben. Selbst im besten Fall macht er aus einem Maulwurfshügel einen Berg.

Seine nächste Behauptung ist, dass C ++ "in die falsche Richtung optimiert" - insbesondere, während er zugibt, dass die Verwendung guter Bibliotheken einfach ist, behauptet er, dass C ++ "das Schreiben guter Bibliotheken fast unmöglich macht". Hier glaube ich, ist einer seiner grundlegendsten Fehler. In Wirklichkeit Bibliotheken gute Schreiben für fast jede Sprache ist extrem schwierig. Das Schreiben einer guten Bibliothek setzt zumindest voraus, dass Sie sich mit einer Problemdomäne so gut auskennen, dass Ihr Code für eine Vielzahl möglicher Anwendungen in dieser Domäne (oder in Bezug auf diese Domäne) funktioniert. Das meiste, was C ++ wirklich tut, ist "die Messlatte höher legen " - nachdem man gesehen hat, wie viel besser eine Bibliothek sein kann , sind die Leute selten bereit, wieder die Art von Dreck zu schreiben, die sie sonst hätten.wirklich gute Programmierer schreiben einige Bibliotheken, die dann (wie er zugibt) von "dem Rest von uns" benutzt werden können. Dies ist wirklich ein Fall, in dem "das ist kein Fehler, es ist eine Funktion."

Ich werde nicht versuchen, jeden Punkt in der Reihenfolge zu treffen (das würde Seiten in Anspruch nehmen), sondern direkt zu seinem Endpunkt springen. Er zitiert Bjarne mit den Worten: "Durch die Optimierung des gesamten Programms können nicht verwendete virtuelle Funktionstabellen und RTTI-Daten entfernt werden. Diese Analyse eignet sich insbesondere für relativ kleine Programme, die keine dynamische Verknüpfung verwenden."

Er kritisiert dies, indem er die Behauptung, "Dies ist ein wirklich schweres Problem", nicht nur mit dem Problem des Stillstands vergleicht. In Wirklichkeit ist es nichts dergleichen - tatsächlich hat der Linker, der in Zortech C ++ (ziemlich genau der erste C ++ - Compiler für MS-DOS in den 1980er Jahren) enthalten war, dies getan. Es ist wahr, dass es schwierig ist, sicher zu sein, dass alle möglicherweise irrelevanten Daten beseitigt wurden, aber immer noch völlig vernünftig, um einen ziemlich fairen Job zu machen.

Unabhängig davon ist jedoch der viel wichtigere Punkt, dass dies für die meisten Programmierer in jedem Fall völlig irrelevant ist. Wie diejenigen von uns, die eine ganze Menge Code zerlegt haben, wissen, enthalten Ihre ausführbaren Dateien mit ziemlicher Sicherheit eine ganze Menge "Zeug" (sowohl Code als auch Daten, in typischen Fällen), die Sie schreiben, es sei denn, Sie schreiben Assemblersprache ohne Bibliotheken wahrscheinlich nicht einmal wissen, ganz zu schweigen von jemals tatsächlich mit. Für die meisten Menschen spielt es meistens keine Rolle - es sei denn, Sie entwickeln für die kleinsten eingebetteten Systeme, ist dieser zusätzliche Speicherverbrauch einfach irrelevant.

Am Ende ist es wahr, dass dieser Schimpanse ein bisschen mehr Substanz hat als Linus 'Idiotie - aber das gibt ihm genau das Verdammnis mit dem schwachen Lob, das es verdient.


1

Als C-Programmierer, der aufgrund unvermeidlicher Umstände in C ++ programmieren musste, habe ich folgende Erfahrungen gemacht. Es gibt nur sehr wenige Dinge, die ich benutze, nämlich C ++ und meistens C. Der Hauptgrund dafür ist, dass ich C ++ nicht so gut verstehe. Ich hatte / habe keinen Mentor, der mir die Feinheiten von C ++ zeigte und wie man guten Code darin schreibt. Und ohne Anleitung von einem sehr sehr guten C ++ - Code ist es extrem schwierig, guten Code in C ++ zu schreiben. Meiner Meinung nach ist dies der größte Nachteil von C ++, da gute C ++ - Programmierer, die bereit sind, Anfänger festzuhalten, nur schwer zu bekommen sind.

Einige der Performance-Hits, die ich normalerweise gesehen habe, sind auf die magische Speicherzuweisung von STL zurückzuführen (ja, Sie können den Allokator ändern, aber wer macht das, wenn er mit C ++ anfängt?). In der Regel hören Sie Argumente von C ++ - Experten, dass Vektoren und Arrays eine ähnliche Leistung bieten, da Vektoren intern Arrays verwenden und die Abstraktion sehr effizient ist. Ich habe festgestellt, dass dies in der Praxis für den Vektorzugriff und das Ändern vorhandener Werte zutrifft. Dies gilt jedoch nicht für das Hinzufügen eines neuen Eintrags, die Konstruktion und Zerstörung von Vektoren. gprof zeigte, dass insgesamt 25% der Zeit für eine Anwendung in Vektorkonstruktoren, Destruktoren, memmove (zum Verschieben des gesamten Vektors zum Hinzufügen neuer Elemente) und anderen überladenen Vektoroperatoren (wie ++) verbracht wurden.

In derselben Anwendung wurde der Vektor "somethingSmall" verwendet, um "somethingBig" darzustellen. Zufälliger Zugriff auf somethingSmall in somethingBig war nicht erforderlich. Es wurde immer noch ein Vektor anstelle einer Liste verwendet. Der Grund, warum Vektor verwendet wurde? Weil der ursprüngliche Codierer mit der Array-ähnlichen Syntax von Vektoren vertraut war und mit den für Listen benötigten Iteratoren nicht sehr vertraut war (ja, er hat einen C-Hintergrund). Es wird weiterhin bewiesen, dass eine Menge Anleitung von Experten erforderlich ist, um C ++ richtig zu machen. C bietet so wenig grundlegende Konstrukte ohne jegliche Abstraktion, dass Sie es viel einfacher als C ++ richtig machen können.



0

STL und Boost sind auf Quellcode-Ebene portabel. Ich denke, was Linus meint, ist, dass C ++ kein ABI (Application Binary Interface) hat. Sie müssen also alle Bibliotheken, mit denen Sie verknüpfen, mit derselben Compilerversion und denselben Schaltern kompilieren oder sich an den DLL-Grenzen auf das C-ABI beschränken. Ich finde das auch ärgerlich. Aber wenn Sie keine Bibliotheken von Drittanbietern erstellen, sollten Sie in der Lage sein, die Kontrolle über Ihre Build-Umgebung zu übernehmen. Ich finde, dass es die Mühe nicht wert ist, mich auf das C ABI zu beschränken. Die Bequemlichkeit, Zeichenfolgen, Vektoren und intelligente Zeiger von einer DLL an eine andere übergeben zu können, ist die Mühe wert, alle Bibliotheken neu erstellen zu müssen, wenn Compiler aktualisiert oder Compiler-Schalter geändert werden. Die goldenen Regeln, denen ich folge, sind:

-Erben Sie die Wiederverwendung der Schnittstelle, nicht die Implementierung

-Bevorzugen Sie die Aggregation über die Vererbung

-Bevorzugen Sie nach Möglichkeit freie Funktionen den Methoden der Mitglieder

- Verwenden Sie immer die RAII-ID, um Ihren Code stark ausnahmesicher zu machen. Versuchen Sie nicht zu fangen.

-Vermeiden Sie mit intelligenten Zeigern nackte (nicht im Besitz befindliche) Zeiger

-Bevorzugen Sie die Wertsemantik auf die Referenzsemantik

-Das Rad nicht neu erfinden, stl und boost verwenden

-Verwenden Sie das Pimpl-Idiom, um private auszublenden und / oder eine Compiler-Firewall bereitzustellen


-6

;Zumindest in einigen Versionen von VC wird kein Finale am Ende einer Klassenerklärung angezeigt.


4
Dies ist vielleicht ein sehr häufiger Fehler für Anfänger (wie fast alles für jemanden, der noch die grundlegende Syntax lernt), aber gibt es viele, die sich kompetent nennen und diesen Fehler dennoch für bemerkenswert halten würden?
Fred Nurk

1
Schrieb es nur, weil der Compiler Ihnen einen Fehler gab, der nichts mit dem Fehlen eines Semikolons zu tun hatte.
Marco Mustapic

2
Ja, genau der gleiche Fehler kommt von einem C-Compiler.
Mircea Chirea
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.