Was passiert genau, wenn ich einen Point mit NULL initialisiere?



  • 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.)



  • Zeus schrieb:

    Verdammt noch mal.... du vergleicht das Verhalten von Programmen, wenn du das Assembler untersuchst, nicht das von Zeiger, oder irgendeinen Smart Pointer.

    Das Assembler hat doch mit dem Verhalten der Pointer nichts zu tun. Das soll nur zeigen das Bloat entsteht durch die Pointer.
    Bei den anderen Zeigern würde zwar kein Bloat entstehen, was aber schlicht und ergreifend daran liegt, dass sie nichts machen, was man nicht auch mit dem rohen Zeiger tun würde.



  • Oh man, der shared_ptr bietet zusätzliche Funktionalität, welche ein normaler Zeiger nicht bietet. Es ist eben nicht nur ein einfacher Wrapper wie z.B. scoped_ptr. Das diese zusätzliche Funktionalität auch zusätzlichen Code benötigt sollte ja wohl klar sein. Wenn man einen shared_ptr benutzt, will man diese Funktionalität in der Regel auch. Damit ist der entstehende zusätzliche Code auch kein “Bloat“, sondern absolut notwendig.
    Dein Vergleich entspricht einem Vergleich zwischen einem PKW und einen Krankenwagen: Wenn man einen Krankenwagen als PKW benutzt ist das ziemlich “bloatig“. In dessen normalem Abwendungsfall ist die zusätzliche Funktionalität aber lebenswichtig.

    Du bist bestimmt auch einer von den Kandidaten die meinen, rohe Arrays sind schneller als ein vector, was?



  • Dann bringen wir halt noch ein weiteres Beispiel, mal sehen welche Begründung die Herren diesmal vorzubringen haben. Wie gesagt der shared_ptr war nur schnell aus dem Hut gezaubert und die zwei Zeiger damit der shared_ptr ansatzweise eine Daseinsberechtigung hatte.

    char * vs. std::string
    


  • Paul Müller schrieb:

    Dann bringen wir halt noch ein weiteres Beispiel, mal sehen welche Begründung die Herren diesmal vorzubringen haben. Wie gesagt der shared_ptr war nur schnell aus dem Hut gezaubert und die zwei Zeiger damit der shared_ptr ansatzweise eine Daseinsberechtigung hatte.

    char * vs. std::string
    

    Tachyon schrieb:

    Du bist bestimmt auch einer von den Kandidaten die meinen, rohe Arrays sind schneller als ein vector, was?

    👍



  • Du verstehst den Punkt einfach nicht, Paul Müller.

    Du behauptest, Klassen würden Codebloat mit sich bringen, den man mit Low-Level Datenstrukturen (wie rohe Zeiger oder Arrays) nicht haben würde. Das stimmt aber nur dann, wenn du die zusätzliche Funktionalität, die Klassen mit sich bringen, und sei es "nur" die Sicherheit immer delete aufzurufen, nicht haben möchtest.

    Wenn du allerdings auch dafür sorgen möchtest, dass zu jeden new ein delete vorhanden ist, oder dass keine Pufferüberläufe entstehen (char* vs. std::string), dann wird der resultierende Code gleich sein, egal ob du es jetzt mit Klassen oder rein prozedural erledigst (auch wenn Exceptionsicherheit nur mit Klassen erreichbar ist). Dass dem so ist, hat SeppJ in seinem Post schön gezeigt.



  • Das ist nicht richtig. Eine Klasse bietet viel mehr Funktionalität, die ich meist gar nicht benötige. Beispielsweise Checks die unnötig sind, weil die Eigenschaften garantiert sind. Diese werde ich wohl kaum nach programmieren. Beispiel char-Array, da allokiere ich mir die Bytes die ich benötigen könnte, um ein realloc zu vermeiden. Damit ist eine bestimmte Größe garantiert und ich benötige auch kein realloc. Ein std::string bietet dir diese Möglichkeit nicht. Dafür bietet dir der std::string durch seine Flexibilität andere Garantien, die natürlich auf kosten der Laufzeit gehen. Bei einem std::string wird man damit leben können, weil bei Text meist keine mehreren GB an Daten anfallen. Bei einer Funktion die Video-Daten verarbeitet sieht es schon wieder anders aus. Da fallen so gewaltige Datenmengen an, dass selbst für den Menschen ein zusätzlicher Maschinenbefehl spürbar werden kann.
    Außerdem scheinen einige zu vergessen, das inlining nur innerhalb einer Übersetzungseinheit funktioniert/funktionieren kann. Es mag Compiler geben, die diese Beschränkung umgehen können, doch der klassische Weg erst compilieren, dann linken, lässt überhaupt keine andere Vorgehensweise zu. Und SeppJ hatte es schon angesprochen alle seine Optimierungen gehen auf Kosten der Compiletime. Wenn man sich aber so die Trends in der Programmierung ansieht geht man lieber auf Kosten der Laufzeit in Richtung Optimierung der Compiletime (zB. Pimpl-Idiom). Ich persönlich finde es auch wesentlich sauberer Klassenbeschreibung und Implementation zu trennen.


  • Mod

    Wenn deine Klassen mehr tun als du möchtest, dann designst du deine Klassen falsch. Das ist deine Schuld und hat überhaupt nichts mit Code-Bloat und all den anderen falschen Behauptungen auf sich die du in diesem Thread aufgestellt hast.


Anmelden zum Antworten