Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

24.01.2015, 11:14

[C++11] Suche Feedback zu meinem CodingStyle

Hi, vor einigen Monaten noch habe ich zwar schon C++11 Features (z.B. auto, range-based loops) verwendet, aber auch grundlegende "Go-Nos" (z.B. prinzipiell Rawpointer statt Smartpointer, Not-Inveted-Yed-Syndrome statt std algorithms). Inzwischen (nach intensiver Lektüre und diversen Videos a la CppCon-Mitschnitte :thumbsup: ) habe ich es geschafft meinen "Coding-Style" zu verbessern. Inzwischen bin ich damit eigentlich relativ zufrieden .. Aber da man bekanntlich manche "Fehler" nicht mehr sieht ("zu nah dran"^^) wäre es hilfreich wenn der ein oder andere mir Feedback geben könnte...

Vor kurzem habe ich begonnen Codestücke meines (unfertigen) Spiels neu zu schreiben und (da sie zwar auf SFML basieren aber noch relativ allgemein sind) aus dem Spiel zu "extrahieren". Dabei herausgekommen ist eine Sammlung von SFML-Erweiterungen, die ich auf GitHub veröffentlicht habe:



Ich wäre dankbar für jedes Feedback zum Code - sowohl aus Sicht des API-Designs, als auch aus Sicht der "Modernität" des Implementierung .. oder auch aus anderen Perspektiven :)

Positives und negatives Feedback ausdrücklich erwünscht :)

LG Glocke

2

24.01.2015, 12:32

z.B. prinzipiell Rawpointer statt Smartpointer

Aber raw-pointer sind nicht obsolet. Sie sind super praktisch, wenn ein Objekt ein anderes nur benutzt und garantiert ist, dass das benutze Objekt länger lebt als das benutzende. Was sehr häufig vorkommt.
Der Vorteil daran ist nicht nur, dass raw-pointer keinen Overhead erzeugen, sondern dass die Semantik auch viel klarer wird. Man sieht einfach schon an der Deklaration, wie das Objekt benutzt wird.

Zum Code: Ich werde mal drüber gucken, wenn ich Zeit habe.
Lieber dumm fragen, als dumm bleiben!

3

24.01.2015, 13:34

Aber raw-pointer sind nicht obsolet. Sie sind super praktisch, wenn ein Objekt ein anderes nur benutzt und garantiert ist, dass das benutze Objekt länger lebt als das benutzende. Was sehr häufig vorkommt.
Der Vorteil daran ist nicht nur, dass raw-pointer keinen Overhead erzeugen, sondern dass die Semantik auch viel klarer wird. Man sieht einfach schon an der Deklaration, wie das Objekt benutzt wird.

Genau! :) Bei manchen rein internen Sachen verwende ich auch noch ein paar davon (z.B. die Cache-Implementierung im Repository ^^ )

Zum Code: Ich werde mal drüber gucken, wenn ich Zeit habe.

Danke ^^

4

24.01.2015, 16:57

Ich habe mal drüber geguckt. Soweit ich es richtig gesehen habe, ist es gar nicht so viel Code, ich habe 3 .cpp und ~8 .hpp Dateien gesehen.
Anzumerken habe ich recht wenig, für mich sieht der Code ansich ganz hübsch aus. Wenn ich damit arbeiten müsste, würde ich mich vermutlich weniger gequält fühlen, als mit so manch anderen Code, den ich in letzter Zeit zu Gesicht bekommen habe :D

Was mich am meisten gestört hat, war die Klammersetzung, erinnerte mich stark an Java und ich mag das überhaupt nicht. Aber das ist eine Stilfrage, und notfalls gibt es automatische Tools um das zu ändern. Ansonsten hast du manchmal in Methoden ein this->var=var; geschrieben. Natürlich ist es eine Stilfrage, wie man seine Variablen benennt (bei mir fangen Klassen groß an, Variablen klein und Member mit m_), aber wenn sich Variablen aufgrund Namensgleichheit überdecken, sehe ich das schon kritischer. Es kann halt leicht zu Verwirrung führen, und so etwas möchte man sicherlich nicht. Natürlich ist es bei so kleinen Funktionen irrelevant, aber vielleicht hat man ja irgendwann mal etwas komplexeres. Du könntest also darüber nachdenken, ein Namensschema einzuführen, dass doppelte Namen versucht zu vermeiden.
Ansonsten fand ich den Kommentarstil ganz passen. Doxygen-Kommentare in den Headern und kurze Kommentare im eigentlichen Code, die Dinge erklären, die nicht direkt offensichtlich sind. Ich war jetzt nicht darauf angewiesen, den Code komplett zu verstehen, aber wäre ich es gewesen, wäre es mir glaube ich nicht sonderlich schwer gefallen. Und ich hab halt viele Kleinigkeiten gesehen, die für mich modernen Code ausmachen, deine Aussage, dich um modernen Code zu bemühen, nimmt man dir also durchaus ab.


Als Tipp noch: Immer dran bleiben. Man findet immer noch irgendetwas, was man lernen kann. Auf Stackoverflow wird z.B: oft Diskutiert, wie man irgendwelche Kleinigkeiten am elegantesten Lösen kann, wodurch man oft nochmal neue Einsichten bekommt. Außerdem gibt es natürlich Videos von Konferenzen, in denen einige der Prominentesten C++ Programmierer Erklärungen und Hintergrundinformationen zu neuen Features geben.
Lieber dumm fragen, als dumm bleiben!

5

24.01.2015, 17:26

Ich habe mal drüber geguckt. Soweit ich es richtig gesehen habe, ist es gar nicht so viel Code, ich habe 3 .cpp und ~8 .hpp Dateien gesehen.

Da bin ich gerade dran. Ich habe einige Template-Spezialisierungen die eigentlich in .cpp Files können - das führt nur gerade zu ein paar weiteren Problemen :D

Naming ist genauso wie die Klammersetzen schon fast eine Glaubensfrage :D Zum this: das habe ich früher übertrieben ^^ .. überall this wo es ging :S Inzwischen mache ich das eigentlich nur bei solchen Namenskollisionen - meist führe ich die aber absichtlich herbei (gerade bei so kleinen Methoden). Die schönste Lösung scheint mir allerdings val = new_val zu sein :)

Danke für deine Mühe :thumbup:

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

6

25.01.2015, 10:50

Mir fällt die inkonsistente Benamsung der Methoden auf. Logger ist so ein Beispiel. Hier hast Du "getLast" und "isEmpty" aber "begin" und "end". Dann die Verwendung von "const" ist auch nur halb durchdacht. Außerdem muss man nicht zwingend immer "auto" verwenden, damit es C++11 Code ist. An manchen Stellen wirkt es bei Dir etwas arg gewollt.
Dann kann man noch über die einzelnen Implementierungen diskutieren. Gerade für Logger gibt es da draußen wesentlich bessere. In Deinem Fall müßte ich in jeder Klasse, wo ich den verwenden will, eine Instanz erstellen.
Aber wir wollen das mal nicht zu schlecht reden da Du ja noch Student bist. Das meine ich jetzt nicht böse. Aber man sieht es am Code.

7

25.01.2015, 10:57

Mir fällt die inkonsistente Benamsung der Methoden auf. Logger ist so ein Beispiel. Hier hast Du "getLast" und "isEmpty" aber "begin" und "end".

Richtig. Allerdings sind begin und end die Ausnahmen. Ich bevorzuge "isEmpty()" über "empty()", verwende aber begin() und end() für die range-based loops. Ich glaube die andere möglichkeit wäre eigene "getBegin()" / "getEnd()" zu schreiben und die funktionen begin(...) und end(...) für meinen Container zu überladen - das erscheint mir aber mit dem Schinken nach der Wurst geschmissen :D
Was würdest du vorschlagen?

Dann die Verwendung von "const" ist auch nur halb durchdacht.

Kannst du da konkrete Fälle nennen?

Außerdem muss man nicht zwingend immer "auto" verwenden, damit es C++11 Code ist. An manchen Stellen wirkt es bei Dir etwas arg gewollt.

Naja ich verwende es an einigen Stellen etwas häufiger, um längere Typen (z.B: sf::Vector2f) abzukürzen wenn klar ist, dass es ein sf::Vector2f ist. Kann sein dass ich es an der ein oder anderen Stelle aber trotzdem übertrieben habe :D
Im Grunde verwende ich auto für folgende Szenarien:
  • für Iteratoren: auto i = std::find(...);
  • für Ergebnisse von Typecasts: auto fpos = static_cast<sf::Vector2f>(pos);
  • und sonst überall wenn der Rückgabetyp relativ lang ist, er aber aus dem Kontext klar ist, z.B. auto& rect = view.getViewport(); (eigentlich kommt da ein sf::FloatRect hin, das ist aber denjenigen Lesern klar, die mit der SFML-Klasse sf::View vertraut sind siehe SFML docs).

Dann kann man noch über die einzelnen Implementierungen diskutieren. Gerade für Logger gibt es da draußen wesentlich bessere. In Deinem Fall müßte ich in jeder Klasse, wo ich den verwenden will, eine Instanz erstellen.

Kannst du das näher erklären? Du kannst deine Logger-Instanz doch an eine Klasse übergeben - oder verwendest eine globale Logger-Variable.

Aber wir wollen das mal nicht zu schlecht reden da Du ja noch Student bist. Das meine ich jetzt nicht böse. Aber man sieht es am Code.

Macht ja nix :D Zumal wir im Studium auch kein C++ thematisieren und ich Lehramts-Student bin (also kein Info Bachelor/Master oder so).

Danke für deine Mühe :)

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Glocke« (25.01.2015, 11:16)


eXpl0it3r

Treue Seele

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

8

26.01.2015, 11:44

Im Grunde verwende ich auto für folgende Szenarien:
für Iteratoren: auto i = std::find(...);
für Ergebnisse von Typecasts: auto fpos = static_cast<sf::Vector2f>(pos);
und sonst überall wenn der Rückgabetyp relativ lang ist, er aber aus dem Kontext klar ist, z.B. auto& rect = view.getViewport();
Die Benutzung von auto geht so ziemlich auf den persönlichen Stil zurück. Ich finde deinen Code etwas mühsam zu lesen, da ich immer zwei Mal überlegen muss, was man da nun für einen Typ erhält/damit arbeitet.

Herb Sutter z.B. verfolgt sein "auto by default" Prinzip, wie zusammengefasst in dieser StackOverflow Antwort lesen kann oder in seinem relativ langen GotW #94.
Im Gegensatz zu Herb Sutters AAA-Style steht z.B. der Artikel von Joseph Mansfield.

Schlussendlich ist es halt wie mit vielem in C++, man muss sich eine Art/einen Weg aussuchen und diesen dann konsequent durchziehen. ;)
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

9

26.01.2015, 12:08

Ich finde deinen Code etwas mühsam zu lesen, da ich immer zwei Mal überlegen muss, was man da nun für einen Typ erhält/damit arbeitet.

Das kann ich mir gut vorstellen :D Gerade bei den Stellen, die den Typ aus einer Funktion meiner API deduzieren ist das nicht einfach. Aber ich denke das ist immer vom Standpunkt des Betrachters abhängig.

Schlussendlich ist es halt wie mit vielem in C++, man muss sich eine Art/einen Weg aussuchen und diesen dann konsequent durchziehen.

Prinzipiell kann jedes Feature over- und underused werden :D Ich denke für beide Fälle (viel auto vs. wenig auto) gibt es jeweils plausible Gründe. Das wichtigste hast du ja gesagt: konsequent - und damit natürlich auch konsistent ^^

LG Glocke

kiba

Alter Hase

Beiträge: 327

Wohnort: NRW

Beruf: Azubi: Fach-Info. Anw.

  • Private Nachricht senden

10

28.01.2015, 17:04

Vll noch etwas als Empfehlung.

Du kannst dir ja mal den http://google-styleguide.googlecode.com/svn/trunk/cppguide.html oder den http://llvm.org/docs/CodingStandards.html anschauen.
Beides kannst du super mit http://clang.llvm.org/extra/clang-modernize.html und den http://clang.llvm.org/docs/ClangFormat.html nutzen und dein Code schön dadurch jagen und dann ist es schon mal einigermaßen "modernisiert" und formatiert.

Ansosnten gibts es noch einige hübsche Talks zu C++11/14 bei der CppCon 2014 und GoingNative 2012.

Werbeanzeige