Bücher zu C++ und OOA/D/P von Stroustrup, Booch, Gamma et al. und anderen
-
Konrad Rudolph schrieb:
Gast++ schrieb:
P.S.: Du polemisierst hier ein wenig.
Ja.
Das lass ich mal so stehen.
Konrad Rudolph schrieb:
Boost nutzt Kapselung, somit auch das OO-Paradigma.
Diese Aussage ist einfach falsch.
Diese Aussage hingegen wäre nur dann zwingend richtig, wenn es keinen Kontext gäbe innerhald dessen wir hier argumentierten.
Konrad Rudolph schrieb:
Aber Deine Aussage ist eine falsche Implikation, genauso wie der berühmt-berüchtigte Syllogismus "Aristoteles ist sterblich. Katzen sind sterblich. Also ist Aristoteles eine Katze."
Das ist aber dann richtig wenn man dabei auf einen Käfig nur mit Katzen und Katzenspielzeug zeigt. Und wir diskutieren hier über hier eine Katze namens C++.
Konrad Rudolph schrieb:
ist nicht jede Verwendung von Klassen OOP.
Genau. Und unter andeerem deshalb führt das auch zu Problemen.
Konrad Rudolph schrieb:
Z.B. ist das Konzept "Ressourcebelegung ist Initialisierung" prozedural nicht abzubilden wenn man sich nicht der besodern Bedeutung von Konstruktoren/Destruktoren gewärtig ist.
-- Weder RAII noch das Konzept von Konstruktor/Destruktor hat zwangsläufig etwas mit OOP zu tun.
Aber gerade die STL schafft hier eine Verbindung und somit auch Notwendigkeiten.
Konrad Rudolph schrieb:
Zugegeben, ich war auch mal so weit, dass ich dachte, OOP sei das absolute Nonplusultra und wenn man schon Klassen verwendet, dann sollte bitte auch *alles* OOP sein. Aber inzwischen habe ich einfach begriffen, dass das nicht zutrifft. Die Ansicht, OOP sei das Nonplusultra ist genauso eine Modeerscheinung wie Hip-Hop oder der Minirock.
Soweit war ich noch nie.
Aber lass uns bitte beim Thema bleiben.
Pro und Contra OOP führt hier zu weit.Grüsse
Gast++
-
Gast++ schrieb:
Da ist mir, wie auch in Deinem folgenden Absatz, zuviel Mustmassung drin:
mov <wohinauchimmer>,[Offset + Displacement]
ginge nämlich auch.
Korrigier mich, wenn's falsch ist aber meinen beschränkten x86-ASM-Kenntnissen zufolgen kann das Displacement nicht eine beliebige Zahl sein sondern nur bestimmte Werte. Zumindest ist das in den meisten Assemblern so. Und damit wäre dieser Opcode ungeeignet.
Konrad Rudolph schrieb:
Die Laufzeit ist n log n,
Das ist nicht die Laufzeit, sondern die Komplexität von Quicksort.
Das ist doch für die Diskussion total egal, zumal ich bereits vorher die Landau-Notation erwähnt hatte. Die Laufzeit ist linear zur Komplexität des Algorithmus. Und damit gilt: Es wird k*n*logn-mal dieser Sprung ausgeführt -- das ist eine Menge!
Die wird durch jeweils einen weiteren Befehl mit konstanter Laufzeit nicht verändert.
Das ist mir bewusst, genau darum geht es aber doch: Der Algorithmus wird um einen konstante Faktor verlangsamt -- und zwar unnötigerweise -- und dieser Faktor ist messbar. Bei aufwendigen Berechnungen kann man sich sowas einfach nicht leisten. Bei einem einfachen Quicksort ist das nicht besonders tragisch aber bei der Sequenzierung eines Genoms entscheidet dieser konstante (!) Faktor darüber, ob das Projekt finanzierbar ist oder nicht. Die Sequenzierung des menschlichen Genoms hat grob zehn Jahre gebraucht! Wenn die Berechnung auch nur um einen Faktor zwei langsamer gewesen wäre, hätte man das Projekt nicht finanzieren können! Bei solchen Größenordnung ist man auf jedes Quentchen Geschwindigkeit angewiesen, selbst auf eine konstante Verbesserung.
Konrad Rudolph schrieb:
Wie und wo wird in dem Projekt eigentlich alloziert?
Was meinst Du damit? Wie Heapspeicher angefodert wird? Wie wir den Speicher verwalten? Oder generell wie Objekte konstruiert werden?
Zwar bin ich mir sicher dass Du Dir das aus dem Kontext erschliessen könntest, aber sei's drum:
Grmpf. Wenn ich es erschlossen hätte, hätte ich nicht nachgefragt. Kaugummidiskussionen machen (zumindest mir) *keinen* Spaß.
Wozu ist denn die Art der Allokation in diesem Kontext interessant?
Sei's drum. Dynamischer Speicher wird in der Bibliothek vorzugsweise über eigene Allokatoren bereitgestellt. Der Standardallokator verwendet intern soweit ich das gerade sehe placement new. Es gibt aber je nach Benutzung recht unterschiedliche Allokationsstrategien.
-
Meine Favoriten sind die hier:
http://www.galileocomputing.de/
-
Konrad Rudolph schrieb:
Gast++ schrieb:
Da ist mir, wie auch in Deinem folgenden Absatz, zuviel Mustmassung drin:
mov <wohinauchimmer>,[Offset + Displacement]
ginge nämlich auch.
Korrigier mich, wenn's falsch ist aber meinen beschränkten x86-ASM-Kenntnissen zufolgen kann das Displacement nicht eine beliebige Zahl sein sondern nur bestimmte Werte. Zumindest ist das in den meisten Assemblern so. Und damit wäre dieser Opcode ungeeignet.
Wieso? Das Displacemt für die "Zeile" ("42. Funktionszeiger...") in der VMT ist konstant.
Nur halt nicht was drinsteht.Anm: [foo] in Assembler meint *foo in C.
Und damit gilt: Es wird k*n*logn-mal dieser Sprung ausgeführt -- das ist eine Menge!
???
Was ist jetzt k?Nein; "der" Sprung wird n*log n ausgeführt und das kostet jeweils (k ?) Takte.
Wobei wir bislang nur über ops sprachen, aber eigentlich wollen wir ja erstaml Takte minimieren.Ausserdem ist die Laufzeit nicht linear zu O(n).
Realiter gibt's da noch
- Caching
- Pipelining / Preemtive Execution
- Threadwechsel
- ggf I/O
- ggf Parallelisierungseffizienz
- ...Da die Faktoren sich teilweise gegenläufig die Laufzeit in Abhängigkeit von n beinflussen wird die Berechung der Laufzeit sehr komplex.
Konrad Rudolph schrieb:
Bei aufwendigen Berechnungen kann man sich sowas einfach nicht leisten. Bei einem einfachen Quicksort ist das nicht besonders tragisch
???
Bei einem Quicksort könnte das nocht am "tragischten" sein, wenn die Operationen trivial sind. Deshalb hattest Du ja wohl auch das Beispiel gewählt.
Wenn die Berechnungen aufwenig sind wird das Verhältnis eines konstanten "Delays" durch die doppelte Indirektion zu den Nutzoperationen doch nur besser...
Vergleich doch mal die Takte für mov mit FPU Instr. Takten.Oder wie meinst Du das jetzt?
Konrad Rudolph schrieb:
Wozu ist denn die Art der Allokation in diesem Kontext interessant?
Weil im Gegensatz zu solch einem kleinen "mov" der Overhead von Systemrufen gigantisch ist.
Konrad Rudolph schrieb:
placement new.
Mit Allokatoren mit überladenem operator void * () als _Where ?
Konrad Rudolph schrieb:
Es gibt aber je nach Benutzung recht unterschiedliche Allokationsstrategien.
Das dachte ich mir jetzt schon irgendwie...
Verstösst _DAS_ schon wieder gegen irgendwelche "Geheimhaltungspflichten"?So kann man schwerlich substantiell diskutieren.
Grüsse
*this
-
Gast++ schrieb:
Konrad Rudolph schrieb:
Bei aufwendigen Berechnungen kann man sich sowas einfach nicht leisten. Bei einem einfachen Quicksort ist das nicht besonders tragisch
???
Bei einem Quicksort könnte das nocht am "tragischten" sein, wenn die Operationen trivial sind.
Natürlich kommt das auf die Datenmengen an. Was ich meinte ist, dass es dann tragisch ist, wenn man Algorithmen hat, die man im Normalfall auf einige hundert Megabytes an Daten anwendet, z.B. Suchalgorithmen (daran arbeite ich gerade). Die atomaren Operationen sind hier auch oft relativ trivial.
Konrad Rudolph schrieb:
Wozu ist denn die Art der Allokation in diesem Kontext interessant?
Weil im Gegensatz zu solch einem kleinen "mov" der Overhead von Systemrufen gigantisch ist.
Das setzt voraus, dass ähnlich oft Speicher angefordert wird, wie Methoden aufgerufen werden werden. Das ist natürlich Quatsch. Dynamischer Speicher wird -- wenn überhaupt -- meistens *einmal* angefordert, zu Beginn des Algorithmus. Die wenigsten Algorithmen benötigen dynamischen Speicher, den man nicht vorher bereits angefordert hat.
Konrad Rudolph schrieb:
Es gibt aber je nach Benutzung recht unterschiedliche Allokationsstrategien.
Das dachte ich mir jetzt schon irgendwie...
Verstösst _DAS_ schon wieder gegen irgendwelche "Geheimhaltungspflichten"?Nein, es ist nur absolut irrelevant für die Diskussion. Für die Diskussion kann man einfach davon ausgehen, dass während eines Algorithmus nur ein einziges Mal Speicher angefordert wird. Das ist natürlich eine Vereinfachung, aber keine extreme.