Ist C++ durch C11 und C14 wieder populärer geworden?



  • Techel schrieb:

    Dafür gibt es die beiliegenden Dokumentation.

    Alle paar Wochen kann ich einen anderen Kollegen mit dem immer selben Witz hochnehmen:
    Neverending runnig gag:

    Er hat fleißig debuggt und kömmt in mein Büro und stellt freundlich aber bestimmt fest, daß es an unseren Funktionen wohl doch liegen wird, daß der Kunde weint. Ich unterbreche meine Arbeit immer sofort und in wenigen Minuten sind wir ganz in der Materie seines Problems. Ganz gewiss nach kurzer Zeit wird er auch mal Zweifel haben, ob er selber dran schuld war, weil er unsere Funktion mit Mist gefütter hat, oder ob unsere Funktion aus Heu Mist erzeugt. Dann verweise ich ihn freundlich auf unsere Dokumentation. Er fragt: "Ach, da gibt es eine Doku? Wo?", und das ganze Büro lacht, das Opfer des Scherzes herzlich mit, daß man ihn wieder drangekriegt hat. Allerbekannt haben wir keine Doku. 🙂



  • Shade Of Mine schrieb:

    Ich sehe das genau umgekehrt: Debugger sind dann genial wenn es nicht um eine limitierte Codestelle geht sondern um komplexe Abhängigkeiten zu anderen Codestellen. Denn lokal limitierte Fehler sind relativ simpel auch ohne Debugger zu finden. Gerade aber wenn die Abhängigkeiten zu anderen Codestellen komplex werden, dann sind Debugger enorm hilfreich.

    Seh ich genauso. Auch gut, wenn man den Prozess nachvollziehbar wiederholen kann. So in der Art, es passiert "etwas", und man hat keine Ahnung, wo das überhaupt herkommt und wer das wozu braucht. Dann findet man raus, was dieses etwas ist und setzt da einen Breakpoint und dann sieht man schon mal im Callstack, wo das ganze herkommt und kann dann nachvollziehen, warum das passiert und wer dafür verantwortlich ist. Oder was wir öfter haben, irgendwelche Prozesse hängen sich ab und zu auf, weil sie in Timing Situationen reinkommen, wo sie gegenseitig aufeinander warten. Dann kann man an der Stelle auch alle Callstacks (sind oft mehrere Threads in jedem Prozess beteiligt) anschauen und dann ist auch oft klar, woran das liegt. Oder einfach irgendwas "durchdebuggen", wo virtuelle Funktionen aufgerufen werden und man erstmal nicht weiß, wo irgendwelche Implementierungen überhaupt herkommen.



  • Also es gibt Dinge die sind einfacher zu debuggen und Dinge die sind schwieriger zu debuggen.
    Die Komplexität des Programms spielt dabei nur begrenzt eine Rolle. Man kann einfache Programme sehr schwer zu debuggen machen aber auch oft komplexe Programme einfach zu debuggen.

    Ein wichtiger Punkt für mich ist dabei wie aussagekräftig der Callstack ist. Wenn der Callstack mich von main() ausgehend, über alle Funktionen die für den aktuellen Zustand des Programms mitverantwortlich sind, bis zu der Stelle hin führt, wo das Problem aufgetreten ist, dann ist das meist super einfach zu debuggen. (Bzw. es sollte halt wenigstens alles im Callstack sein was für den Zustand der Problematischen Variablen/Objekte verantwortlich ist.)

    Wenn der Callstack nur aus main->DispatchMessage->(50 Level Framework-/OS-Funktionen)->OnDingsiEvent besteht, dann wird es schwieriger. Callstacks ala main->Dingsi::Run->Dingsi::CallHandler->(10 Framework/OS Funktionen)->[AnonymousCompletionHandlerClass42]::operator() sind auch nicht schön.

    Und ein zweiter wichtiger Punkt ist für mich wie einfach bzw. schwer es überhaupt möglich ist sinnvolle Breakpoints zu setzen. Das kann z.B. dadurch deutlich erschwert werden dass übertrieben "generisch" (nicht im Sinn von Templates jetzt) programmiert wurde und zu viel in Config-Files verlagert.

    Ist schwer zu beschreiben ohne Romane zu verfassen (die dann verständlicherweise keiner liest), aber ich versuchs mal...

    Ich denke da an eines unserer Programme (mit dem ich gottseidank kaum zu tun habe). Das Ding instanziert per XML File gesteuert haufenweise "Dinge" Objekte. Meist Integer-Dinge, String-Dinge, manchmal Container-Dinge. Und dann gibt es auch noch die lustigen "Objekt-Dinge". Wobei ein "Objekt-Ding" eine Map ist die "benannte Dinge" enthält. Also nen Namen auf ein (abstraktes!) Ding abbildet. So wird dann ein lustiger Dinge-Graph aufgebaut -- ausgehend von einem zentralen, globalen Wurzel-Ding. Mit dem Debugger so ein "Ding" zu inspizieren ist also schonmal super-mega-umständlich. Denn erstmal muss man das Ding von der Wurzel ausgehend überhaupt mal finden.

    Weites sind die Dinge natürlich auch beobachtbar, haben also Change-Listener. An die kann man verschiedene Observer-Klassen dranhängen, natürlich auch alles per XML konfiguriert. Das ganze geht sogar so weit dass man z.B. per XML File Bedingungen definieren kann die noch geprüft werden sollen bevor der konfigurierte Handler aufgerufen werden soll. Die Bedingungen sind natürlich ebenso Objektgraphen, also z.B. Or-Objekte die dann Kinderlein haben die sie verodern, Equals-Checker Objekte die wieder irgendwelche "Dinge" auf Gleichheit prüfen usw.
    Und natürlich gibt es auch konfigurierbare "wiederverwendbare" Handler-Klassen. Die Dinge kopieren, auf einen bestimmten Wert setzen, Container-Dinge ausleeren - lauter so lustige Sachen.

    Jetzt ist der Fehler dass wenn man dieses oder jenes macht bzw. dem Programm füttert, danach das Ding "Foo.Bar.Baz[42].SchrunsTschagguns.NumberOfBatsInTheRoof" den falschen Wert hat - es fehlt eine Fledermaus.

    Und nu' setz nen sinnvollen Breakpoint.

    Klar, man kann sich irgendwie behelfen. Man kann ne eigene Dummy-Handler Klasse schreiben, und die im XML File beim Ding "Foo.Bar.Baz[42].SchrunsTschagguns.NumberOfBatsInTheRoof" als "Changed" Handler eintragen. Dann kann man in der Handler-Funktion der Dummy-Handler Klasse nen Breakpoint setzen. [Sarkasmus]Geht ja schnell.[/Sarkasmus]
    Und dann hat man nen tausende Zeilen langen Callstack voll mit lauter generischen, nichtssagenden Klassennamen.



  • @volkard:
    Danke für die ausführliche Erklärung. OOP scheint ja doch eine Menge Vorteile zu haben.



  • Jetzt ist der Fehler dass wenn man dieses oder jenes macht bzw. dem Programm füttert, danach das Ding "Foo.Bar.Baz[42].SchrunsTschagguns.NumberOfBatsInTheRoof" den falschen Wert hat - es fehlt eine Fledermaus.

    Und nu' setz nen sinnvollen Breakpoint.

    Klar, man kann sich irgendwie behelfen. Man kann ne eigene Dummy-Handler Klasse schreiben, und die im XML File beim Ding "Foo.Bar.Baz[42].SchrunsTschagguns.NumberOfBatsInTheRoof" als "Changed" Handler eintragen. Dann kann man in der Handler-Funktion der Dummy-Handler Klasse nen Breakpoint setzen. [Sarkasmus]Geht ja schnell.[/Sarkasmus]
    Und dann hat man nen tausende Zeilen langen Callstack voll mit lauter generischen, nichtssagenden Klassennamen.

    wunderbares Beispiel für zu frühe Abstraktion / oder Vermischung von Aufgabe und mächtigem Interface - besser währe es echte harte Klassen zu haben (so wie sosnt auch) die wirklich die Aufgabe ausführen und dafür Tests - das kann man dann debuggen

    und die ich bin ein "Ding"-Welt komplett drumherum stülpen - also nicht ich bin schon in meiner Wurzel ein Ding sondern - ich sehe so aus und verhalten mich wie ein Ding



  • @Gast3
    Mir ist schon klar dass das ein furchtbares Design ist und wie man es verbessern könnte. Ich wollte es nur als Beispiel bringen für etwas was dazu führt dass man sich enorm schwer tut beim Debuggen.



  • Wie viel Software mit furchtbaren Design gibt es da draußen?



  • Wie viel Software mit furchtbaren Design gibt es da draußen?

    sehr viel - Sandkörner am Strand kommt wohl nah drann 🙂



  • Das Problem mit der meißten Software (auch bei uns wenn wir die Designen und dann umsetzen) ist aus meiner Sicht oft entweder zu wenig designed zu haben oder im anderen Fall Overengineering.

    Gerade der 2. Fall ist weder praktisch noch sinnvoll, da man einfach zu viel unnötige Arbeit in das Design gesteckt hat und am Ende viel zu viel abstrahiert hat und es keiner mehr versteht.



  • @inflames2k
    Deswegen bin ich ein Freund von XP.
    Also zumindest teilweise.
    Drauf los coden, probieren, Schwachstellen erkennen, refactoren, repeat.
    Wenn man dabei keine Angst hat beim Punkt "refactoren" ggf. auch gröber umzubauen geht das nach meiner Erfahrung sehr gut, und auch das Ergebnis wird meist sehr gut.

    Man muss es halt durchziehen. Die Zeit die man beim refactoren verliert hat man sich vorher bei der Planung gespart bzw. spart man sich nachher beim nicht-fixen-müssen von Problemen die nicht auftreten.

    Wenn man das nicht schafft, weil Chef/... meint es wäre schlauer man nicht so viel ru refactoren und dafür lieber zu "machen"... dann isses halt für A.

    (Dass man nen groben Plan haben sollte, damit man wenigstens mal so a grobes Block-Diagramm machen kann was sich ca. in welchem Modul abspielen wird, sollte klar sein. Aber dafür braucht ma ka Ewigkeit.)


Anmelden zum Antworten