Was passiert genau, wenn ich einen Point mit NULL initialisiere?
-
Warum soll das ein Vergleich von Äpfeln mit UFOs sein? Der Code macht das gleiche und darum geht es. Es war nicht gefragt die Aussage von SeppJ zu bekräftigen, indem ich eine Klasse suche, die genauso wenig Code wie ein roher Zeiger erzeugt.
-
Der Code von Drakon ist doch nicht mehr als ein schlechter Scherz, welchen Sinn versprichst du dir von deinem "Wrapper"? Also ein wenig Ernsthaftigkeit sollte schon dabei. Auch wenn ich es mit einem Extrembeispiel etwas auf die Spitze getrieben habe.
-
Paul Müller schrieb:
Der Code von Drakon ist doch nicht mehr als ein schlechter Scherz, welchen Sinn versprichst du dir von deinem "Wrapper"? Also ein wenig Ernsthaftigkeit sollte schon dabei. Auch wenn ich es mit einem Extrembeispiel etwas auf die Spitze getrieben habe.
Das ist nicht mehr als dein Code auch macht. Wenn du mehr/anderes Verhalten haben willst, dann wird natürlich auch mehr Code erzeugt. Dass das so nicht viel Sinn macht ist ja wohl klar, aber es ist Abstraktion, die (bei einem guten Compiler) nichts kostet.
Warum soll das ein Vergleich von Äpfeln mit UFOs sein? Der Code macht das gleiche und darum geht es. Es war nicht gefragt die Aussage von SeppJ zu bekräftigen, indem ich eine Klasse suche, die genauso wenig Code wie ein roher Zeiger erzeugt.
Er macht nicht ganz das gleiche, nein. Der Smart Pointer weiss was alles referenziert wird und man muss sich da nicht selbst darum kümmern.
Wenn du den Teil aus dem Smart Pointer rausnimmst wird das Beispiel genau gleich schnell sein. Das Beispiel von SeppJ oben illustriert das auch recht gut.
-
Paul Müller schrieb:
...Also ein wenig Ernsthaftigkeit sollte schon dabei...
Dann fasse dir bitte auch mal selbst an die Nase. Ein scoped_ptr oder auto_ptr käme ja wenigstens noch in die Funktionelle Nähe eines reinen Zeigers. Ein shared_ptr erfüllt aber wesentlich mehr als nur einen Zeiger zu wrappen, und ist dann sinnvoll wenn eine Referenzzählung nötig ist, weil nicht sicher gestellt werden kann welcher der verwendeten Stellen, die letzte ist.
Wenn muss man wirklich auch gleiches mit gleichen vergleichen. Und dann kostet OO und Templates nicht viel, und bringen zudem richtig eingesetzt auch zusätzliche Sicherheit und Wartbarkeit mit fast 0 Mehrkosten.
Nachtrag: Und wenn wir schon Äpfel mit Birnen vergleichen, kann ich ja auch gleich das Gegenbeispiel bringen. Ein Programmierer meinte mir gegenüber immer das die Standardbibliothek etc. soviel mehr kosten, und baute sich daher eine auf seine Fälle "optimierte" Fassung zurecht, die fast ausschließlich prozedural geschrieben war. Als ich irgendwann diesen Code benutzen musste, und einen Fehler darin fand, tauschte ich das spaßeshalber mal mit einen mehr an "Abstraktion" aus (Und unter Verwendung von Klassen und der Standardbibliothek). Nicht nur das der Code danach ungefähr ein Zehntel so groß (und verständlicher) war, lief er auch noch um ein Drittel schneller.
Geschwindigkeit ist nicht nur durch einzelne Codestellen, sondern auch in Kombination zu sehen. Und wenn gleichzeitig Wartungsaspekte hinzu kommen, habe ich in der Praxis nicht selten erlebt das lesbarer Code nicht selten sogar genauso schnell (oder gar schneller) als die Handoptimierten war.
-
Die Aufgabe war aber nicht Abstraktion so anzupassen, dass sie keinen zusätzlichen Code erzeugt, sondern dass sie sinnvoll ist.
Und bei deiner Abstraktion geht jeglicher Sinn verloren. Meine macht dahingehend Sinn, dass beide Zeiger gültig sind, so wie im Ursprungsprogramm gefordert. Und ich muss mich nicht selber um das delete oder bei dir destroy kümmern, wofür ich ja eigentlich hier die Abstraktion einsetze. Und zu guter Letzt ich ändere nicht einfach eine bestehende Klasse. Was auch ein Punkt von sinnvoller Abstraktion ist.
-
Paul Müller schrieb:
Die Aufgabe war aber nicht Abstraktion so anzupassen, dass sie keinen zusätzlichen Code erzeugt, sondern dass sie sinnvoll ist.
Sinnvoll und vergleichbar, was dem Vergleich reiner Zeiger gegenüber shared_ptr eindeutig widerspricht. Du wirst ja hoffentlich auch nicht für 50m Fußweg ein Auto verwenden.
Paul Müller schrieb:
Meine macht dahingehend Sinn, dass beide Zeiger gültig sind, so wie im Ursprungsprogramm gefordert.
Aber du nimmst absichtlich für den Fall ungeeignete Beispiele.
Paul Müller schrieb:
Und zu guter Letzt ich ändere nicht einfach eine bestehende Klasse. Was auch ein Punkt von sinnvoller Abstraktion ist.
Aber auch bei der Verwendung bestehender Klassen nimmt man die passenden. Wenn eine Schraube leicht locker ist, rufe ich ja auch nicht gleich den Fachmann an, sondern nehme einen Schraubenzieher zur Hand.
-
Deine Abstraktion ist auch nicht sehr sinnvoll. shared_ptr benutzt man nicht, um in einem Scope ein kurzlebiges Objekt zu verwalten, sondern um ein Objekt in multiplen Kontexten verwalten zu können. In dem Beispiel wäre ein scoped_ptr sinnvoll. Das würde auch wieder vergleichbaren ASM-Code erzeugen.
-
Es ging bei meinen Beispiel nur darum die Aussage von SeppJ zu widerlegen, dass die Nutzung von Klassen niemals Bloat nach sich zieht. Da hab einfach das erstbeste genommen, wo ich mir sicher war. Die extreme sehe ich eher als Unterstützung meiner Aussage. Dass der Code absolut keinen Sinn ergibt ist dabei nicht von Bedeutung.
-
Wenn Du für Deine Zeiger manuell eine Referenzzählung durchführen würdest, dann würde im Vergleich kein „bloat“ entstehen. Funktional wäre es dann auch vergleichbar. So ist Dein Beispiel einfach Nonsense.
-
Tachyon schrieb:
Deine Abstraktion ist auch nicht sehr sinnvoll.
Das war auch nicht gefordert. Es wurde nur nach einem Beispiel verlangt.
Tachyon schrieb:
In dem Beispiel wäre ein scoped_ptr sinnvoll.
Nein wäre er nicht, weil er nicht dupliziert werden kann. Ich will über den Sinn nicht streiten, der Sinn ist ein äquivalentes Code Verhalten. Es geht hier auch nicht um den shared_ptr, sondern um eine Klasse die bloat erzeugt und da ist der shared_ptr nunmal ein gutes Beispiel. Und auch ein praxisrelevantes Objekt.
-
Tachyon schrieb:
Wenn Du für Deine Zeiger manuell eine Referenzzählung durchführen würdest, dann würde im Vergleich kein „bloat“ entstehen. Funktional wäre es dann auch vergleichbar. So ist Dein Beispiel einfach Nonsense.
Nein es wäre funktional nicht vergleichbar. Weil keine Referenzzählung vorgesehen ist. Die macht nur der shared_ptr, damit ich den Luxus hab kein delete aufrufen zu müssen. Wär mir dieser Luxus egal und das ist er mir persönlich, dann würde ich auch keine Verwendung für eine Abstraktion haben.
-
Paul Müller schrieb:
Tachyon schrieb:
Deine Abstraktion ist auch nicht sehr sinnvoll.
Das war auch nicht gefordert. Es wurde nur nach einem Beispiel verlangt.
Paul Müller schrieb:
Die Aufgabe war aber nicht Abstraktion so anzupassen, dass sie keinen zusätzlichen Code erzeugt, sondern dass sie sinnvoll ist.
Was denn nun?
-
Paul Müller schrieb:
Tachyon schrieb:
Deine Abstraktion ist auch nicht sehr sinnvoll.
Das war auch nicht gefordert. Es wurde nur nach einem Beispiel verlangt.
Tachyon schrieb:
In dem Beispiel wäre ein scoped_ptr sinnvoll.
Nein wäre er nicht, weil er nicht dupliziert werden kann. Ich will über den Sinn nicht streiten, der Sinn ist ein äquivalentes Code Verhalten. Es geht hier auch nicht um den shared_ptr, sondern um eine Klasse die bloat erzeugt und da ist der shared_ptr nunmal ein gutes Beispiel. Und auch ein praxisrelevantes Objekt.
Das ist es doch, deine beide Beispiele haben nicht das gleiche äquivalentes Code Verhalten.
Oder muss ich deutlicher werden:
Das Verhalten deines Programm ist das Verhalten, welches du selbst geschrieben hast, und das Verhalten, dass du nutzt.
-
Es wurde ganz deutlich nach einem Beispiel gefragt, welches beweisen soll, dass ctor-/dtor-Aufrufe Performanceeinbußen generieren. Du hast bisher keins vorgelegt, dass deine These glaubhaft unterstützt.
-
Tachyon schrieb:
Was denn nun?
In Bezug auf die Verwendung eines Wrappers. Ob das Beispiel Sinn macht ist doch egal.
Zeus schrieb:
Das ist es doch, deine beide Beispiele haben nicht das gleiche äquivalentes Code Verhalten.
Wo liegt der Unterschied?
-
Herrlich, Paul Müller weiß ganz genau, dass er Unsinn geredet hat, aber ist zu stolz es zuzugeben. Jetzt verstrickt er sich schon in Widersprüchen.
Gib's einfach zu: Du hast Mist erzählt. Wahre Größe zeigt der, der seine Fehler eingesteht.
-
Paul Müller schrieb:
Zeus schrieb:
Das ist es doch, deine beide Beispiele haben nicht das gleiche äquivalentes Code Verhalten.
Wo liegt der Unterschied?
Zeus schrieb:
Oder muss ich deutlicher werden:
Das Verhalten deines Programm ist das Verhalten, welches du selbst geschrieben hast, und das Verhalten, dass du nutzt.
-
Zeus schrieb:
Das Verhalten deines Programm ist das Verhalten, welches du selbst geschrieben hast, und das Verhalten, dass du nutzt.
Ja und dieses Verhalten ist zwei Zeiger, die beide auf das selbe mit new erzeugte Objekt zeigen. Wenn ich nun alle hier vorgeschlagenen Lösungen für einen Wrapper vergleiche, so bietet mir nur der shared_ptr diese Funktionalität. Die Lösung von drakon zwar auch, diese bietet aber sonst keinen Mehrwert.
HighLigerBiMBam schrieb:
Es wurde ganz deutlich nach einem Beispiel gefragt, welches beweisen soll, dass ctor-/dtor-Aufrufe Performanceeinbußen generieren. Du hast bisher keins vorgelegt, dass deine These glaubhaft unterstützt.
Schein ich zwar überlesen zu haben, aber auch dafür hab ich was gebastelt.
int main() { int bar(42); // einfach nur ein int return 0; }
Einen Wrapper der einen Wert hält und nicht speziell für dieses Problem entworfen wurde. Sicher werd ich deswegen auch wieder gesteinigt. Der vector ist einfach nur eine Aufwendige Initialisierung, die zwar im speziellen Fall nicht benötigt wird, aber zum allgemeinen Objekt gehört. Weil der vector irgendwann, zum Beispiel für eine History, benötigt wird.
Ja das ist ein konstruiertes Beispiel, aber es ist nicht abwegig und deswegen bitte ich meine mangelnde Kreativität zu entschuldigen.#include <vector> class Foo { std::vector<int> m_vec; int m_bar; public: Foo(int bar) : m_vec(1024), m_bar(bar) {} }; int main() { Foo foo(42); return 0; }
.file "bar.cpp" .text .p2align 4,,15 .globl main .type main, @function main: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 xorl %eax, %eax movl %esp, %ebp .cfi_offset 5, -8 .cfi_def_cfa_register 5 popl %ebp .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (GNU) 4.5.2" .section .note.GNU-stack,"",@progbits
.file "foo.cpp" .text .p2align 4,,15 .globl main .type main, @function main: .LFB446: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 movl %esp, %ebp .cfi_offset 5, -8 .cfi_def_cfa_register 5 andl $-16, %esp subl $16, %esp movl $4096, (%esp) call _Znwj leal 4096(%eax), %ecx movl %eax, %edx .p2align 4,,7 .p2align 3 .L2: movl $0, (%edx) addl $4, %edx cmpl %ecx, %edx jne .L2 testl %eax, %eax je .L10 movl %eax, (%esp) call _ZdlPv .L10: xorl %eax, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE446: .size main, .-main .ident "GCC: (GNU) 4.5.2" .section .note.GNU-stack,"",@progbits
-
Verdammt noch mal.... du vergleicht das Verhalten von Programmen, wenn du das Assembler untersuchst, nicht das von Zeiger, oder irgendeinen Smart Pointer.
-
Da kann ich auch Crysis mit Doom vergleichen. Resultat = fail.
Einen Wrapper der einen Wert hält und nicht speziell für dieses Problem entworfen wurde. Sicher werd ich deswegen auch wieder gesteinigt. Der vector ist einfach nur eine Aufwendige Initialisierung, die zwar im speziellen Fall nicht benötigt wird, aber zum allgemeinen Objekt gehört. Weil der vector irgendwann, zum Beispiel für eine History, benötigt wird.
Dann implementiere DIE GLEICHE MÖGLICHKEIT auch in den obigen Code mit der selben FUNKTIONALITÄT, aber ohne Klasse!
Edit: Ich denke der Thread führt zu nichts mehr und ist längst vom Thema abgewichen. Deshalb sollte er geschlossen werden. (Auch wenn ich ihn belustigend finde.)