Frage an alle die denken, dynamisches casting ist ein Zeichen von schlechtem Softwaredesign
-
mgaeckler schrieb:
Mag sein. Der Terminus Fehler bezeichnet für mich eine Eigenart, die geändert werden muß.
Dann ist der Terminus bei Dir falsch belegt, fürchte ich.
Nehmen wir uns mal das Posting von DocShoe. Er schreibt da von einem Herrn Meyer, auf den man nicht so hören soll. Eindeutig ein Fehler. Der gemeinte Mann heißt Meyers. Trotzdem besteht absolut kein Bedarf, das zu ändern.
-
volkard schrieb:
Dann ist der Terminus bei Dir falsch belegt, fürchte ich.
Nehmen wir uns mal das Posting von DocShoe. Er schreibt da von einem Herrn Meyer, auf den man nicht so hören soll. Eindeutig ein Fehler. Der gemeinte Mann heißt Meyers. Trotzdem besteht absolut kein Bedarf, das zu ändern.Vielleicht solltest du dir das Posting mal richtig durchlesen, statt nur auf Details wie Namen zu achten. Ich habe nicht behauptet, immer auf Meyers Techniken zu verzichten, sondern zu überlegen, ob sie für den eigenen Anwendungsfall nützlich und anwendbar sind. Klar kann ich mehrere zig Zeilen Code schreiben, der eine Designschwäche behebt, aber den Code aufbläht und dafür andere Nachteile mit sich bringt. Das stoische Anwenden von Schema F auf Problem P ist nicht immer die beste Lösung.
-
DocShoe schrieb:
volkard schrieb:
Dann ist der Terminus bei Dir falsch belegt, fürchte ich.
Nehmen wir uns mal das Posting von DocShoe. Er schreibt da von einem Herrn Meyer, auf den man nicht so hören soll. Eindeutig ein Fehler. Der gemeinte Mann heißt Meyers. Trotzdem besteht absolut kein Bedarf, das zu ändern.Vielleicht solltest du dir das Posting mal richtig durchlesen, statt nur auf Details wie Namen zu achten. Ich habe nicht behauptet, immer auf Meyers Techniken zu verzichten, sondern zu überlegen, ob sie für den eigenen Anwendungsfall nützlich und anwendbar sind. Klar kann ich mehrere zig Zeilen Code schreiben, der eine Designschwäche behebt, aber den Code aufbläht und dafür andere Nachteile mit sich bringt. Das stoische Anwenden von Schema F auf Problem P ist nicht immer die beste Lösung.
Ich fühle mich rundherum mißverstanden.
-
Gnihihi, dein Beitrag lässt aber auch genug Spielraum für Fehlinterpretationen. Du solltest klarstellen, worin der Fehler liegt, um weiteren Missverständnissen vorzubeugen.
-
volkard schrieb:
Wenn dynamic_cast klappt, hast Du eh die vtbl im code und den vptr in jedem Objekt. Da wird durch eine weitere virtuelle Funktion nichts langsamer.
Doch. Die Programme, die diese Bibliothek benutzen werden größer und zwar alle unabhängig davon, ob sie die Funktionen alle nutzen oder nicht. Das macht die Programme daher zwangsweise langsamer. Ob sich das bemerkbar macht oder nicht, hängt natürlich vom Einzelfall ab. In einem Fall ging es um eine Lasttestanwendung, die möglichst viel Last auf einem Server generieren sollte ohne aber selbst unnötig Overhead zu erzeugen.
mfg Martin
-
DocShoe schrieb:
Gnihihi, dein Beitrag lässt aber auch genug Spielraum für Fehlinterpretationen. Du solltest klarstellen, worin der Fehler liegt, um weiteren Missverständnissen vorzubeugen.
Der Fehler ist das vergessene s im Namen. Das ist einerseits eindeutig ein Fehler und andererseits völlig unwichtig und muß nicht repariert werden. Es war ein naheliegendes Beispiel, um den Terminus "Fehler" ein wenig zu rücken.
-
volkard schrieb:
DocShoe schrieb:
Gnihihi, dein Beitrag lässt aber auch genug Spielraum für Fehlinterpretationen. Du solltest klarstellen, worin der Fehler liegt, um weiteren Missverständnissen vorzubeugen.
Der Fehler ist das vergessene s im Namen. Das ist einerseits eindeutig ein Fehler und andererseits völlig unwichtig und muß nicht repariert werden. Es war ein naheliegendes Beispiel, um den Terminus "Fehler" ein wenig zu rücken.
Wurde mir dann auch klar... du hättest dich aber auch auf "auf den man nicht hören soll" beziehen können, was deinem Beitrag einen ganz anderen Sinn gegeben hätte.
-
mgaeckler schrieb:
Doch. Die Programme, die diese Bibliothek benutzen werden größer
Was wird grösser? Der zusätzliche VTable-Eintrag?
mgaeckler schrieb:
Das macht die Programme daher zwangsweise langsamer.
Aber daran, dass
dynamic_castin vielen Implementierungen sehr langsam ist, denkst du nicht.mgaeckler schrieb:
Ob sich das bemerkbar macht oder nicht, hängt natürlich vom Einzelfall ab. In einem Fall ging es um eine Lasttestanwendung, die möglichst viel Last auf einem Server generieren sollte ohne aber selbst unnötig Overhead zu erzeugen.
Ja, und genau deshalb solltest du messen. Erst recht, wenn es um eine zeitkritische Anwendung geht. Bitte meide nicht virtuelle Funktionen und weiche auf fragwürdige Alternativen wie
dynamic_castaus, weil du das Gefühl hast, virtuelle Funktionen seien langsam.
-
volkard schrieb:
mgaeckler schrieb:
Mag sein. Der Terminus Fehler bezeichnet für mich eine Eigenart, die geändert werden muß.
Dann ist der Terminus bei Dir falsch belegt, fürchte ich.
Nehmen wir uns mal das Posting von DocShoe. Er schreibt da von einem Herrn Meyer, auf den man nicht so hören soll. Eindeutig ein Fehler. Der gemeinte Mann heißt Meyers. Trotzdem besteht absolut kein Bedarf, das zu ändern.Na gut. Es gibt Fehler mit denen man Leben kann. Wir sprachen aber von Designfehlern einer Bibliothek. Darüber würde ich nicht so einfach hinweg sehen wollen.
mfg Martin
-
mgaeckler schrieb:
volkard schrieb:
Wenn dynamic_cast klappt, hast Du eh die vtbl im code und den vptr in jedem Objekt. Da wird durch eine weitere virtuelle Funktion nichts langsamer.
Doch. Die Programme, die diese Bibliothek benutzen werden größer und zwar alle unabhängig davon, ob sie die Funktionen alle nutzen oder nicht. Das macht die Programme daher zwangsweise langsamer. Ob sich das bemerkbar macht oder nicht, hängt natürlich vom Einzelfall ab. In einem Fall ging es um eine Lasttestanwendung, die möglichst viel Last auf einem Server generieren sollte ohne aber selbst unnötig Overhead zu erzeugen.
mfg MartinTja, ohne dynamic_cast hättest Du die rtti-Tables nicht gebaraucht und vielleicht so mehr Platz gespart. Und dynamic_cast kann extram langsam sein. 1k RAM mehr zu benötigen ist keine Schande mehr. Da müßte man schon extrem genau messen können, um einen Effekt auf die Laufzeit nachzuweisen. Und wo soll das hinführen. Verzicht auf die Benutzung von std::string, weil es Anwender geben könnte, die selber kein std::string brauchen und deswegen dann eine kleinere ausführbare Datei hätten?
Die Entscheidung von Dir scheint eine Überlegung zu sein, wo das letzte Promille Speed herausgequetscht werden soll. Dann würde ich mal schauen, ob man schummeln kann. Zum Beispiel
#ifdef MSVC unsigned long ::getTypeID(IBase* self){return *reinterpret_cast<unsigned int*>(self);} //liest einfach den vptr aus. //zerfällt je nach dem zu einem schnellen asm-befehl //oder zu nur einer anderen adressierung eines anderen befehls. #endifedit: Freie Funktion aus der Methode gemacht. WIllst ja nicht in die Klasse eingreifen müssen.
-
Nexus schrieb:
mgaeckler schrieb:
Doch. Die Programme, die diese Bibliothek benutzen werden größer
Was wird grösser? Der zusätzliche VTable-Eintrag?
Die 4 oder 8 Extrabyte der VTable sind natürlich irrelevant. Aber es müssen ja dann auch alle Funktionen dazugebunden werden. Das sind dann schon deutlich mehr als 4 Byte.
Nexus schrieb:
mgaeckler schrieb:
Das macht die Programme daher zwangsweise langsamer.
Aber daran, dass
dynamic_castin vielen Implementierungen sehr langsam ist, denkst du nicht.Doch natürlich. Nur: Die Anwendung, die den dynamic cast benutzt hat, war ein simpler XML-Editor. Die Reaktionszeit war immer noch kürzer als ein Augenschlag des Anwenders dauert, trotz des furchtbaren dynamic casts.
Nexus schrieb:
mgaeckler schrieb:
Ob sich das bemerkbar macht oder nicht, hängt natürlich vom Einzelfall ab. In einem Fall ging es um eine Lasttestanwendung, die möglichst viel Last auf einem Server generieren sollte ohne aber selbst unnötig Overhead zu erzeugen.
Ja, und genau deshalb solltest du messen. Erst recht, wenn es um eine zeitkritische Anwendung geht. Bitte meide nicht virtuelle Funktionen und weiche auf fragwürdige Alternativen wie
dynamic_castaus, weil du das Gefühl hast, virtuelle Funktionen seien langsam.Ich habe nie geschrieben, daß virtuelle Funktionen langsam sind. Ich habe geschrieben, daß sie Overhead erzeugen, der manchmal nicht aktzeptabel ist und ich habe auch ein Beispiel genannt.
Der Lasttest ist in der Lage, das Verhalten von 1000 Benutzern und mehr zu simulieren. Dazu stehen dann aber natürlich nicht 1000 Rechner zu Verfügung. Der Lasttest darf dann natürlich nicht selbst zum Flaschenhals werden, sonst misst man/frau an der falschen Stelle.
mfg Martin
-
mgaeckler schrieb:
Die 4 oder 8 Extrabyte der VTable sind natürlich irrelevant. Aber es müssen ja dann auch alle Funktionen dazugebunden werden. Das sind dann schon deutlich mehr als 4 Byte.
Nicht benötigte Funktionen müssen nicht zwingend gelinkt werden. Das hängt von den Optimierungsmöglichkeiten des Compilers ab. Aber selbst wenn: Glaubst du,
dynamic_castbrauche keinen Code für die Logik des Typ-Bestimmens zur Laufzeit?mgaeckler schrieb:
Doch natürlich. Nur: Die Anwendung, die den dynamic cast benutzt hat, war ein simpler XML-Editor. Die Reaktionszeit war immer noch kürzer als ein Augenschlag des Anwenders dauert, trotz des furchtbaren dynamic casts.
Aber mit dem Overhead der virtuellen Funktion hätte es knapp nicht mehr gereicht, verstehe.
mgaeckler schrieb:
Ich habe nie geschrieben, daß virtuelle Funktionen langsam sind. Ich habe geschrieben, daß sie Overhead erzeugen, der manchmal nicht aktzeptabel ist und ich habe auch ein Beispiel genannt.
Natürlich sind virtuelle Funktionen manchmal unangebracht. Deswegen sind Methoden in C++ standardmässig auch nicht virtuell. Nur ist es etwas fragwürdig, durch eine Annahme bezüglich des Overheads zu einem anderen Sprachmittel zu greifen, das nicht gerade wenige Nachteile hat.
Wenn du nach ausführlichem Profiling zum Schluss gekommen wärst, dass
dynamic_casttatsächlich die bessere Lösung sei, und dass die Umstellung überhaupt relevanten Einfluss auf die Gesamt-Performance hat, dann okay. Aber so wie du es bisher beschrieben hast, scheinen deine Design-Entscheidungen eher auf Annahmen und Überlegungen zu basieren. Und diese können oft falsch sein, weil man die genaue Implementierung nicht kennt, weil etliche Faktoren dazukommen, oder weil man sich generell schnell verschätzen kann.
-
Wie ich das verstanden habe:
Es gibt eine schlanke XML-Bibliothek, wo diese Funktionalität fehlt.Das Programm Lasttest benutzt die Bibliothek und freut sich über das eingesparte Kilobyte. Lasttest soll so schnell wie möglich sein. Lasttest braucht die Funktionalität nicht.
Das Programm XML-Editor braucht die Funktionalität und nimmt einfach dynamic_cast. Der XML-Editor kann beliebig inperformant sein.
Es bleibt, daß ich auch hier dynamic_cast für schlecht halte und lieber die Bibliothek aufmotzen würde. Falls sie aus dem eigenen Hause stammt oder ich sonst einfachen Einfluß darauf habe.
Und es bleibt
die Aussage, dynamisches casten sei ein Zeichen schlechten Softwaredesigns, ist völliger Humbug.
kann man nicht so stehen lassen.
-
Nexus schrieb:
Wenn du nach ausführlichem Profiling zum Schluss gekommen wärst, dass
dynamic_casttatsächlich die bessere Lösung sei, und dass die Umstellung überhaupt relevanten Einfluss auf die Gesamt-Performance hat, dann okay. Aber so wie du es bisher beschrieben hast, scheinen deine Design-Entscheidungen eher auf Annahmen und Überlegungen zu basieren. Und diese können oft falsch sein, weil man die genaue Implementierung nicht kennt, weil etliche Faktoren dazukommen, oder weil man sich generell schnell verschätzen kann.Ich merke schon. Wir reden aneinander vorbei.
Ich habe eine Bibliothek zur XML Verarbeitung. Die Bibliothek wird von mehreren Anwendungen benutzt.
Eine dieser Anwendung ist ein simpler XML Editor. Der hat performance mässig kein Problem, der darf den dynamic cast benutzen, weil der Bibliothek eine Eigenschaft nicht liefert.
Eine andere Anwendung, die mit dem XML-Editor nur gemeinsam hat, daß sie auch die Bibliothek benutzt, ist ein Lasttestprogramm. Diese darf selber kein Flaschenhals sein. Die Bibliothek wird daher nur allgemeine Eigenschaften bzw. Fähigkeiten zur Verfügung stellen, die von allgemeiner Bedeutung sind. Irgendwelche Spezialfälle, die nur für den XML Editor wichtig sind, der keine Performanceprobleme hat, kommen daher nicht in die Bibliothek. Natürlich benutzt auch die XML-Lib virtuelle Funktionen, wo immer es erforderlich ist.
Und, das Lasttestprogramm selber wurde natürlich einem genauen Profiling unterworfen, damit es eben kein Flaschenhals ist.
mfg Martin
-
Ah, okay. Ob es sich bei der fehlenden Methode wirklich um einen Designfehler in der XML-Bibliothek handelt, hängt natürlich davon ab, wie die Bibliothek im Allgemeinen benutzt werden soll. Also nicht nur auf den Editor bezogen.
Denn wäre es wirklich nur ein editor-spezifisches Problem, das
dynamic_casterfordert, so ist es gut möglich, dass entsprechender Clientcode im Editor eine andere Lösung alsdynamic_castfindet. Aber ich kenne das konkrete Design zu wenig.Schlussendlich ist es auch nicht tragisch,
dynamic_casteinmal einzusetzen. Nur sollte man sich dessen Nachteile bewusst sein (und Performance ist oft nicht der entscheidende Nachteil), und allfällige Alternativen in Erwägung ziehen.
-
volkard schrieb:
Wie ich das verstanden habe:
Es gibt eine schlanke XML-Bibliothek, wo diese Funktionalität fehlt.Das Programm Lasttest benutzt die Bibliothek und freut sich über das eingesparte Kilobyte. Lasttest soll so schnell wie möglich sein. Lasttest braucht die Funktionalität nicht.
Das Programm XML-Editor braucht die Funktionalität und nimmt einfach dynamic_cast. Der XML-Editor kann beliebig inperformant sein.
So ähnlich kannst Du es formulieren. "beliebig inperformant" ist allerdings etwas übertrieben.

volkard schrieb:
Es bleibt, daß ich auch hier dynamic_cast für schlecht halte und lieber die Bibliothek aufmotzen würde. Falls sie aus dem eigenen Hause stammt oder ich sonst einfachen Einfluß darauf habe.
Der XML-Standard ist nicht sehr volatil. Und gerade weil alles aus einer Hand stammt, kann ich sehr gut auf Veränderungen reagieren. Aber eines ist mir natürlich bewusst, wenn ich die Bibliothek veröffentlichen würde, wären natürlich andere Anforderungen an diese zu stellen und die Effizienz müsste darunter "leiden", da in diesem Falle natürlich die Abstraktion auf ein wesentlich höheres Niveau steigen muß als es jetzt ist.
volkard schrieb:
Und es bleibt
die Aussage, dynamisches casten sei ein Zeichen schlechten Softwaredesigns, ist völliger Humbug.
kann man nicht so stehen lassen.
Ich seh ein, da habe wohl ich übertrieben.
mfg Martin
-
Hei Leut, mal wieder zurück zum Thema! :p
Also ich habe das Ganze mittlerweile mit dem double dispatcher Pattern implementiert und funktioniert auch ganz dolle. Nun kommt aber gleich wieder ein Problem und zwar muss ich die BoundingVolumeHierarchie rendern (zu Debugginzwecken). Der Renderer muss also IMHO die BoundingVolumes kennen, umgekehrt aber nicht. Nun ist es so, dass bspw. eine BoundingSphere vollständig anders gerendert wird, als eine kDOP oder eine OOB. Ausserdem haben diese natürlich auch ganz andere Membervariablen. Für die Physikengine ist es gut gelöst, die kommuniziert nämlich ausschliesslich im der Abstrakten Klasse BoundingVolume und muss nichts über die interne Geometry wissen. Die will nur wissen, hat eine Kollision stattgefunden und falls ja an welcher Stelle im kartesichen Raum. Der Renderer hingegen muss nun sehr genau wissen, wie die Geometry des entsprechenden Proxykörpers aufgebaut ist. Da aber eine BVH ein Baum von BoundingVolumes ist frage ich mich, wie ich dies nun ohne dynamic_cast lösen kann?
-
Warum nicht? Die virtuelle Funktion im Objekt weiß doch, welches BoundingVolume passend ist.
-
Ja aber nicht welches Mesh für das Rendern verwendet werden soll, da die BoundingVolume nichts mit Grafik am Hut hat. Ausserdem werden OBB's als Indexed line list, kDops als indexed Trianglelists und BoundingSpheres als vorgeladenes Mesh gerendert. Alles Informationen, über welche die BoundingVolume nicht verfügt, der Renderer hingegen schon. Dafür weiss der Renderer ohne dynamic_cast nicht, wie die Paramater der jeweiligen geometrischen Form aussehen.
So nun bin ich gespannt!

-
Wie siehts mit dem Visitorpattern aus?
IVolume* vol; Renderer r; vol->accept(r); // vol ruft dann die passende Methode im Renderer aufSozusagen SingleDispatching anders rum