Unterschied zwischen leerem Destruktor und default Desktruktor


  • Mod

    @tggc sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    @seppj: So wie ich es grad erklaert hatte, müsste ja genau das eben gar nicht passieren.

    Wieso? Deine Erklärung führt ganz exakt zu dem Problem, was ich beschrieben habe.

    Noch einmal ganz ausführlich:
    std::copy hat zwei Pfade, einen für POD und einen für non-POD. An der Stelle kann prinzipiell nur auf Existenz oder nicht-Existenz eines Destruktors geprüft werden, nicht auf Inhalt. Denn dies ist Templatemagie, keine Compileroptimierung. Der POD-Pfad führt zu einem expliziten memmove-Aufruf. Das geht, weil der Autor von std::copy ganz genau die Semantik der copy-Funktion kennt und weiß, dass die Funktionalität in diesem Fall äquivalent zu einem memmove ist. Der andere Pfad führt zu einer Schleife in der Art, wie sie im Beispiel des Threaderstellers benutzt wird. Danach greift der Optimierer und kann zum Beispiel leere Destruktoraufrufe in der Schleife wegoptimieren.

    Jetzt willst du ernsthaft einen Optimierer bauen, der for-Schleifen semantisch(!) analysiert und erkennt, dass die for-Schleife aus dem Beispiel durch ein memmove ersetzbar ist? Hast du irgendeine Ahnung, wie weit die Informatik davon weg ist? Viel Spaß beim Beweis, ob die Schleife überhaupt hält...


  • Mod

    @sewing sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    ja ok, pimpl idion sehe ich ein als Ausnahmefall, aber nochmal zurück zu meinem eingangspost:

    Wieso wird hier = default als remedy verkauft statt einem leeren Dtor?

    Weil der default eben etwas anderes ist als ein expliziter, leerer Destruktor. Default (und keine Angabe) sagen ausdrücklich und unmissverständlich aus, dass es sich um den automatisch generierten Destruktor handelt (und das Objekt somit als POD handhabbbar ist). Beim leeren Destruktor musst du:

    1. Den Destruktor kennen. Das heißt, das geht nicht in Templates. Und es geht auch nicht, wenn der Destruktor in einer anderen Übersetzungseinheit steht. Das ist schon einmal sehr, sehr einschränkend, denn Templatemagie ist nicht so selten in modernem C++. Sogar recht häufig. Und verschiedene Übersetzungseinheiten sind auch sehr häufig.
    2. Dann musst du auch noch beweisen, dass der Destruktor nichts tut. Ok, das ist noch schaffbar, aber halt eine weitere Verkomplizierung, die dafür sorgt, dass das nur der Compiler machen kann und keine noch so clevere Implementierung auf Seite des Nutzers oder der Standardbibliothek. Und es gilt wieder, dass der Destruktor dafür auch vorliegen muss und nicht etwa in einer anderen Übersetzungseinheit liegt.

    Wenn bekannt ist, dass der Destruktor der default-Destruktor ist, dann entfallen diese Schwierigkeiten komplett.



  • dann verstehe ich aber nicht, wieso in vielen Beispielen virtual ~Dtor() = default;

    immer angeführt wird als Beispiel um zu zeigen, dass in diesem Fall keine move operationen vom compiler synthetisiert werden, wenn es doch offenbar in dem von mir genannten Beispiel doch funktioniert



  • Ja, aber wuerde es nicht reichen ein bool has_empty_destructor()<T> einzufuehren um das Problem zu loesen, oder nicht?

    Das Unrollen einer Schleife mit konstant 64 Schritten wird übrigens von einigen Compilern gemacht, wir sind nicht also auch nicht soweit davon entfernt.


  • Mod

    @tggc sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Ja, aber wuerde es nicht reichen ein bool has_empty_destructor()<T> einzufuehren um das Problem zu loesen, oder nicht?

    Wie soll das funktionieren? Soll das Template den Code inspizieren?

    Das Unrollen einer Schleife mit konstant 64 Schritten wird übrigens von einigen Compilern gemacht, wir sind nicht also auch nicht soweit davon entfernt.

    Es ist auch ungleich einfacher zu erkennen, wie oft eine Schleife läuft, als zu erkennen, was der Unterschied des Programmzustands zwischen Beginn und Abschluss einer Schleife ist. Selbst wenn wir mal Aliasing raus lassen (was dies noch einmal unendlich viel schwerer machen würde und daher vom Sprachstandard quasi wegdefiniert wurde), müsste der Optimierer erkennen, dass ein Stück Code den gleichen Effekt hat wie memmove. Soll ich dir hier ein Dutzend Codeschnipsel zeigen und du sagst mir dazu, ob diese exakt durch eine bekannte C-Funktion ersetzbar sind und wenn ja, durch welche? Mal schauen, wie schwer sich ein Mensch dabei tut.


  • Mod

    @sewing sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    dann verstehe ich aber nicht, wieso in vielen Beispielen virtual ~Dtor() = default;
    immer angeführt wird als Beispiel um zu zeigen, dass in diesem Fall keine move operationen vom compiler synthetisiert werden, wenn es doch offenbar in dem von mir genannten Beispiel doch funktioniert

    Holla! Zwischen dem default-erzeugten Destruktor und einem virtuellen default-erzeugten Destruktor ist ein Riesenunterschied. virtual und POD passt so überhaupt gar nicht zusammen. Der Compiler muss hier schließlich Code für die copy-Funktion erzeugen, der auch noch den vtable updated (oder wie auch immer der Compiler die Virtualität implementiert). Wie du bei godbolt sehen kannst, ist das sogar noch eine Stufe mehr Code als nur mit leerem Destruktor. memmove ist da offensichtlich komplett ausgeschlossen.


  • Mod

    @seppj sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    @sewing sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    ja ok, pimpl idion sehe ich ein als Ausnahmefall, aber nochmal zurück zu meinem eingangspost:

    Wieso wird hier = default als remedy verkauft statt einem leeren Dtor?

    Weil der default eben etwas anderes ist als ein expliziter, leerer Destruktor. Default (und keine Angabe) sagen ausdrücklich und unmissverständlich aus, dass es sich um den automatisch generierten Destruktor handelt (und das Objekt somit als POD handhabbbar ist). Beim leeren Destruktor musst du:

    1. Den Destruktor kennen. Das heißt, das geht nicht in Templates.

    Weshalb? (Bzw. wie meinst Du das?)

    1. Dann musst du auch noch beweisen, dass der Destruktor nichts tut. Ok, das ist noch schaffbar, aber halt eine weitere Verkomplizierung, die dafür sorgt, dass das nur der Compiler machen kann und keine noch so clevere Implementierung auf Seite des Nutzers oder der Standardbibliothek.

    Wir sprechen von einer Optimierung. Der absolute Großteil aller Optimierungen basiert auf Informationen die der Compiler durch dataflow/controlflow/etc. analysis herleitet.

    Und es gilt wieder, dass der Destruktor dafür auch vorliegen muss und nicht etwa in einer anderen Übersetzungseinheit liegt.

    Ein leerer Destruktor wird selten in einer anderen Übersetzungseinheit liegen, aber uns muss dieser Fall auch gar nicht kümmern.

    Wenn bekannt ist, dass der Destruktor der default-Destruktor ist, dann entfallen diese Schwierigkeiten komplett.

    Das bedeutet nicht, dass ein Compiler keinen Anreiz hat, ein gängiges Anti-Idiom wie eine leere Definition von Destruktoren zu berücksichtigen. Weil es, grob gesagt, immer noch um Amdahl's law geht. Wenn genug Trottel solchen Code schreiben, wird er Compiler einfach eine entsprechende, hardgecodete Abfrage integrieren wollen. Warum versuchst Du, dieses Problem mit viel schwereren, allgemein unentscheidbaren zu assoziieren? Ein leerer Destruktor kann syntaktisch erkannt und in einem Kontext erfasst werden, welcher dann dem Optimierer zur Verfügung steht. Wer hat von nicht-trivialen Beispielen gesprochen?

    @seppj sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    @tggc sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Ja, aber wuerde es nicht reichen ein bool has_empty_destructor()<T> einzufuehren um das Problem zu loesen, oder nicht?

    Wie soll das funktionieren? Soll das Template den Code inspizieren?

    Ich verstehe den Einwand nicht. Es wurden schon einige Traits (in der stdlib) eingeführt, die nicht mittels der Sprache allein implementiert werden können.


  • Mod

    Ich habe es jetzt schon 2x genau erklärt. Ich erkläre es nicht noch einmal, bloß weil ihr die objektive Realität nicht akzeptieren wollt.


  • Mod

    Du willst offenbar nicht zwischen Durchgeführtem und Durchführbarkeit differenzieren. Dass Implementierungen Destruktoren ohne Effekt, die als {} definiert wurden, nicht ignorieren, bedeutet nicht, dass das schwer wäre. Sondern dass bislang kein Anreiz dafür bestand. Ich wollte hier auch lediglich erwähnen, dass die Basisfälle (wie eben {}) völlig unproblematisch sind, und auch eine gute Portion aller realen Fälle von effektfreien Destruktoren ausmachen. Mir (und @TGGC) ist schon klar, dass Compiler nicht blöd genug sind, aussichtslose Analysen laufen zu lassen.


  • Mod

    @c-olumbo sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Du willst offenbar nicht zwischen Durchgeführtem und Durchführbarkeit differenzieren. Dass Implementierungen Destruktoren ohne Effekt, die als {} definiert wurden, nicht ignorieren, bedeutet nicht, dass das schwer wäre. Sondern dass bislang kein Anreiz dafür bestand. Ich wollte hier auch lediglich erwähnen, dass die Basisfälle (wie eben {}) völlig unproblematisch sind, und auch eine gute Portion aller realen Fälle von effektfreien Destruktoren ausmachen. Mir (und @TGGC) ist schon klar, dass Compiler nicht blöd genug sind, aussichtslose Analysen laufen zu lassen.

    Du willst nicht die Schwierigkeit erkennen! Zu der Zeit, wo es einfach ist, die Optimierung durchzuführen, ist es nahezu unmöglich schwer, die nötigen Voraussetzungen zu erkennen. Und zu der Zeit, wo es einfach ist, die nötigen Voraussetzungen zu erkennen, ist es nahezu unmöglich schwer, die Optimierung durchzuführen. Da kannst du auch nicht einfach so etwas dran ändern, ohne die ganze Sprache komplett umzukrempeln, weil die Ursachen tief darin verankert sind, wie die Sprache definiert ist und welche Folgen dies dafür hat, wie die Verarbeitungsreihenfolge bei der Übersetzung ist (und dass die Sprache so definiert ist, hat wiederum Gründe darin, wie man besonders gut Übersetzer schreiben kann). Du kannst nicht einfach die Realität umdefinieren, weil sie dir nicht gefällt!

    Ich habe nun schon sehr oft die genaue Erklärung wiederholt, jedes weitere "Warum?" verweise ich auf meine vorherigen Erklärungen. Du kannst den Fakt, dass es so ist, ganz einfach mit jedem Compiler nachvollziehen. Meine schlüssige Erklärung kannst du akzeptieren oder eben den Rest der Menschheit für blöd erklären, weil sie in Jahrzehnten von Optimierungsforschung nicht auf die Lösung gekommen ist, die du dir heute Nachmittag ausgedacht hast.

    @c-olumbo sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Ich verstehe den Einwand nicht. Es wurden schon einige Traits (in der stdlib) eingeführt, die nicht mittels der Sprache allein implementiert werden können.

    Nenn ein einziges Trait, das Codeinspektion voraussetzt. Es gibt kein einziges. Wenn du verstehst warum, dann hast du verstanden, wieso dein angeblich so einfaches Vorhaben so schwer ist. Sämtliche Traits beziehen sich auf die Definitionen und Eigenschaften von Datenstrukturen, die keine Realität im späteren Maschinencode haben.

    Es gibt ein paar Traits, die ein bisschen in die Richtung Inspektion gehen, wie die is_nothrow_Xable. Wie du aber merken wirst, beziehen diese sich bloß auf die explizite Markierung der untersuchten Objekte mittels noexcept ähnlichem. Also Versprechen, die der Programmierer an dieser Stelle machen kann, damit Optimierungen frühzeitig durchgeführt werden können, wo es Sinn macht, und der Compiler kann dann bei einem späteren Durchgang prüfen, ob das Versprechen auch gehalten wurde. Aber umgekehrt kann der Compiler nicht frühzeitig sagen, ob etwas noexcept ist, außer der Programmierer gibt ihm dieses Versprechen. Das =default geht in die gleiche Richtung und tatsächlich gibt es ja auch jede Menge Traits, die sich darauf beziehen.


  • Mod

    Ich glaube, Du verwechselst hier etwas, aber es ist schwer das zu erkennen, weil Du dich so unglaublich vage ausdrückst, und außerdem glaube ich, dass Du meine Aussage irgendwie allgemeiner interpretierst, als ich sie artikuliert habe—es geht mir hier erst einmal nur um den lexikalisch leeren Destruktor. Soweit ich raten kann, beziehst Du dich auf die streng getrennten Phasen der Übersetzung in denen einmal ein AST mit der ganzen C++-spezifischen Information, und andererseits ein simpler IR Code (LLVM oder RTL) auf dem semantische Flussanalysen ausgeführt werden können, gegeben ist, wobei wir keine Abbildung zwischen beiden zur Verfügung haben. Ich stimme zu, dass wir i.A. nicht hoffen können, dass ein Compiler bestimmen kann, dass eine Funktion dieses oder jenes Verhalten hat, und diese Information wiederum der höheren Phase anbietet, um Typisierung zu lösen. Das würde schließlich mehrfache Iteration beider Phasen zur Folge haben, aber noch viel wichtiger, es würde Typisierung von semantischen Qualitäten abhängig machen, was gerade dringlichst zu vermeiden ist.

    Hier geht es aber nicht um Semantik, sondern Syntax. Das Trait kann implementiert werden, indem wir eine simple, grammatische Untermenge von C++ erfassen, die keine semantischen Effekte hat. Das Endresultat wäre syntax & type driven.

    Es wäre sogar möglich, im Standard selbst vorzugeben, dass leere Destruktoren die lexikalisch innerhalb der Klasse liegen, besonders berücksichtigt werden, und triviale Zerstörbarkeit nicht ausschließen, nur um dir mal zu vergegenwärtigen, dass mein konkretes Beispiel einfacher ist, als Du es ausmachst... nicht, dass solche Dinge etwas in den Sprachregeln verloren hätten!

    Es gibt ein paar Traits, die ein bisschen in die Richtung Inspektion gehen, wie die is_nothrow_Xable. Wie du aber merken wirst, beziehen diese sich bloß auf die explizite Markierung der untersuchten Objekte mittels noexcept ähnlichem. Also Versprechen, die der Programmierer an dieser Stelle machen kann, damit Optimierungen frühzeitig durchgeführt werden können, wo es Sinn macht, und der Compiler kann dann bei einem späteren Durchgang prüfen, ob das Versprechen auch gehalten wurde. Aber umgekehrt kann der Compiler nicht frühzeitig sagen, ob etwas noexcept ist, außer der Programmierer gibt ihm dieses Versprechen. Das =default geht in die gleiche Richtung und tatsächlich gibt es ja auch jede Menge Traits, die sich darauf beziehen.

    Das klingt nicht sonderlich überzeugend; siehe bspw. die Diskussionen/Paper bzgl. Deduktion von constexpr(auto) und noexcept(auto). Hier muss der Compiler in einer höheren Phase den Inhalt einer Funktion inspizieren und ein entsprechendes Attribut an diese Funktion anheften. Ich bin aber auch unsicher, was Du mit "Codeinspektion" meinst, also semantische oder syntaktische Inspektion.



  • @seppj sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    @tggc sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Ja, aber wuerde es nicht reichen ein bool has_empty_destructor()<T> einzufuehren um das Problem zu loesen, oder nicht?

    Wie soll das funktionieren? Soll das Template den Code inspizieren?

    Im simpelsten Fall Schreibt man sich ein Macro, was einen leeren Konstruktor und das gleichzeitig definiert.

    Das Buch sagt doch ersetze alle ~T(){} mit ~T() = default. Und diese simple Anweisung ist offensichtlich auch maschinell ausführbar, wenn du meinst das wäre nicht so das musst du schon mit einem Argument kommen und nicht nur "ja das ist eben unendlich schwer.". Und wie gesagt ist selbst das für mich kein Argument, denn grundsätzlich bedeutet das auch erstmal nichts.

    Vorhin meintest du ja auch erst:
    @seppj sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Viel Spaß beim Beweis, ob die Schleife überhaupt hält...
    Na und das geht ja offensichtlich.

    @seppj sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Es ist auch ungleich einfacher zu erkennen, wie oft eine Schleife läuft, als zu erkennen, was der Unterschied des Programmzustands zwischen Beginn und Abschluss einer Schleife ist.

    Aber das war auch gar nicht die Aufgabe. Was wenn nur eine ganz bestimmte Schleife erkannt werden, z.b. eine die ohnehin unrolled wird? Das unrollen beweist ja schon, das es erkennbar ist. Oder eine simple peephole Optimization, welche zwei mov hintereinander ersetzt wenn die Adresse aufeinanderfolgen, diese Regel kann dann wiederholt angewendet werden. So fundamental ist dieses Problem nicht, wie du es machen willst. Eher so uninteressant, das es keinen interessiert.

    Und umgekehrt würde auch hier ein minimale Anpassung reichen:
    http://en.cppreference.com/w/cpp/concept/TriviallyCopyable

    Wir bräuchten hier nur sagen das ein trivial destructor auch ein leerer inline Destruktor sein kann fuer TriviallyCopyable2 und das dann an entsprechenden Stellen benutzen. Und auch hier höre ich gern deine Begründung warum " ~T() = default" das ausloesen kann, "~T(){}" aber nicht.


  • Mod

    @tggc sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Das Buch sagt doch ersetze alle ~T(){} mit ~T() = default. Und diese simple Anweisung ist offensichtlich auch maschinell ausführbar, wenn du meinst das wäre nicht so das musst du schon mit einem Argument kommen und nicht nur "ja das ist eben unendlich schwer.". Und wie gesagt ist selbst das für mich kein Argument, denn grundsätzlich bedeutet das auch erstmal nichts.

    Bist du da so sicher? Als Beweis, dass ich hier keine obskuren Beispiele heranziehe, an denen ich lange getüftelt habe¹, nehmen wir doch einfach mal das Beispiel aus dem Buch. Das ist simpel. Keine Tricks, keine Überladungen, Templatemagie, keine Sichtbarkeitsklugscheißereien, keine virtuellen Funktionen, keine Vererbung. einfach nur ein struct mit zwei int Membern. Einfacher geht es nicht. Das sollte doch ohne Probleme funktionieren, oder?

    #include <iostream>
    
    struct Point
    {
      int x,y;
      ~Point(){}
    };
    
    int main()
    {
      Point p;
      std::cout << p.x << ' ' << p.y << '\n';  // Ein bisschen Entropie, um meinen Zufallsgenerator zu initialisieren.
    }
    

    Jetzt ersetzen wir einfach den Destruktor durch den default.

    #include <iostream>
    
    struct Point
    {
      int x,y;
      ~Point()=default;
    };
    
    int main()
    {
      Point p;
      std::cout << p.x << ' ' << p.y << '\n';  // Hoppla, alles 0?
    }
    

    Ups.

    Wie ich schon sagte: Ihr beiden seid eindeutig die einzigen beiden klugen Menschen auf der Welt. Ihr habt an einem Nachmittag gelöst, woran andere seit Jahrzehnten verzweifeln.Und das obwohl ihr euch schwer tut mit der Erklärung, wieso andere ein Problem damit haben. Die anderen sind schlieslich alle dumm und ihr habt als einzige die Lücken in der Erklärung erkannt.

    ¹: Wer weiß, was in der Sprache des most vexing parse so alles möglich ist? Bist du wirklich in der Lage, zu beweisen, dass dein Vorschlag mit allen der vielen möglichen Schweinereien funktioniert?


  • Mod

    @seppj sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Wie ich schon sagte: Ihr beiden seid eindeutig die einzigen beiden klugen Menschen auf der Welt. Ihr habt an einem Nachmittag gelöst, woran andere seit Jahrzehnten verzweifeln.Und das obwohl ihr euch schwer tut mit der Erklärung, wieso andere ein Problem damit haben. Die anderen sind schlieslich alle dumm und ihr habt als einzige die Lücken in der Erklärung erkannt.

    Aber am Ende bist schlieslich Du derjenige, der klug ist.

    Und dein erster Code ist undefiniert.

    Und Du hast dich nicht einmal auf meine letzte Antwort bezogen.



  • Warum erklärst du nicht, was der Unterschied ist, ich habe doch schon mehrfach danach gefragt? Oder weisst du es nicht? Nach der Logik ist die Aussage des Buches ja auch falsch, da man die Varianten nicht einfach austauschen darf. Also nochmal, warum ist ein POD trivial kopierbar, aber die Point struct nicht?

    Dein Beispiel ist aus meiner Sicht Unsinn, weil da ja ehh was beliebiges passieren darf, also auch eine beliebige Optimierung angewandt werden darf. Dieser Grundsatz dürfte dir ja bekannt sein.


  • Mod

    @tggc sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Warum erklärst du nicht, was der Unterschied ist, ich habe doch schon mehrfach danach gefragt? Oder weisst du es nicht? Nach der Logik ist die Aussage des Buches ja auch falsch, da man die Varianten nicht einfach austauschen darf. Also nochmal, warum ist ein POD trivial kopierbar, aber die Point struct nicht?

    Weil das Konzept trivialer Kopierbarkeit—welches u.a. auch als Trait im Typsystem eine Rolle spielt—nicht von dem Inhalt einer Funktion abhängen sollte, selbst wenn man diesen (wie ich oben erwähnt habe) grammatisch beschränken kann. Willst Du als nächstes operator= als trivial markieren, wenn dieser ein memcpy durchführt? SeppJ hat schon Recht, dass der allgemeine Fall nicht realistisch entscheidbar ist, und daher brauchen wir die ganze Abteilung "Funktionskörper" gar nicht anfassen.


  • Mod

    Ich habe es jetzt 2x ausführlich erklärt. Den Fakt, dass idie Optimierung nicht gemacht wird, obwohl sie das beobachtbare Verhalten nicht ändern würde, könnt ihr mit jedem Compiler nachvollziehen, egal ob ihr meine Erklärung nun versteht oder nicht. Was soll ich da noch mehr tun? Mehr Beispiele liefern, wieso es nicht so einfach ist? Ihr akzeptiert nicht einmal das denkbar einfachste Beispiel, das ich nicht einmal selbst schreiben musste, sondern einfach unverändert das Simpelbeispiel des TE genommen habe. Da ist doch ausgeschlossen, dass euch obskurere Beispiele helfen.

    Ihr habt also:

    • Objektiv prüfbare Fakten, dass die Vorgeschlagene Optimierung nicht gemacht wird
    • Eine Erklärung dazu, wieso es technisch schwierig bis unmöglich ist, die vorgeschlagene Optimierung durchzuführen
    • Gegenbeispiele zu eurer Gegenerklärung, wieso ihr denkt, dass das alles ganz einfach wäre

    Und ihr sagt trotzdem "Nein, das glaube ich nicht". Was soll ich da noch weiter machen? Nein, beantwortet diese Frage nicht, ich sehe nämlich keinen Sinn, noch mehr zu liefern. Es ist alles gesagt, jede weitere Antwort wäre eine Wiederholung des bereits gesagtem mit anderen Worten. Das könnt ihr oben selber nachlesen.


  • Mod

    @seppj Hä? Dein Beispiel oben ist unzulässig, weil es undefiniert ist. Da ist es völlig wurscht, welchen Effekt unsere Umschreibung hat.

    Und Du hast dich wieder nicht auf meine Antwort bezogen. Zitiere mal einen Teil davon, und erkläre mir, wo ich etwas missverstanden habe. Und deine Erklärung ist sowas von absoluter bs:

    Jetzt willst du ernsthaft einen Optimierer bauen, der for-Schleifen semantisch(!) analysiert und erkennt, dass die for-Schleife aus dem Beispiel durch ein memmove ersetzbar ist?

    Willst du mich jetzt völlig veralbern oder was? Das ist schon längst gängige Praxis!



  • Also aus meiner Sicht ist es Wurst ob es schon gemacht wird oder nicht. Für mich ist "es wird nicht gemacht" und daraus folgt es ist sehr schwer oder auch unmöglich keine logische Begründung. Mit glauben hat das ja nun nichts zu tun. Würde mich daher freuen, wenn auf meine Anmerkung genauer eingegangen wird.



  • @seppj sagte in Unterschied zwischen leerem Destruktor und default Desktruktor:

    Jetzt ersetzen wir einfach den Destruktor durch den default.

    #include <iostream>
    
    struct Point
    {
      int x,y;
      ~Point()=default;
    };
    
    int main()
    {
      Point p;
      std::cout << p.x << ' ' << p.y << '\n';  // Hoppla, alles 0?
    }
    

    Ups.

    Muss da nicht Point p = Point(); oder sowas stehen damit man hier zero-init bekommt? War zumindest mal so...


Anmelden zum Antworten