drei fragen zum c++ standard



  • frage 1:
    wieso gibt es kein placement delete?
    x ist eine klasse, für die der new-operatoren so überladen wurde, dass er einen parameter nimmt: eine andere klasse, die für die allokation des speichers verantwortlich is.

    class x;
    class heap;
    
    heap h;
    x* X = new(h) X; // möglich.
    delete(h) x; // unmöglich.
    

    die frage stellt sich, wieso das unmöglich ist? wo ist das problem mit einem placement delete?

    frage 2:
    const constructor.

    class x {
      x(void); // ok
      x(void) const; // nicht ok
    };
    

    auch hier stellt sich die frage, wieso das nicht möglich ist. grundsätzlich ist der typ der variable und damit auch immer const bzw. non-const zum zeitpunkt des aufrufs des konstruktors bestimmt. das gilt natürlich auch für die konstruktoren aller basisklassen.

    frage 3:
    wieso ist this ein pointer? dafür gibt es keinen grund. this ist im prinzip für eine klasse x ein pointer vom typ

    x* const
    

    bzw

    const x* const
    

    . eine referenz ist genau das. initialisiert ist this auch immer automatisch. die semantik bezüglich const und non-const ist für pointer und referenzen die gleiche.



    1. es gibt placement delete, bloss nicht so wie du dir das vorstellst. die placement delete funktion wird, so vorhanden, automatisch aufgerufen falls der constructor eine exception wirft. die signatur muss dabei mit der der verwendeten placement new funktion übereinstimmen.

    wenn du so ein objekt löschen willst nachdem es erfolgreich konstruiert wurde kannst du es so machen:

    class x;
    class heap;
    
    heap h;
    x* X = new(h) X; // möglich.
    //delete(h) x; // unmöglich. 
    
    void* p = &x;
    x->X::~X(); // dtor aufrufen
    h.deallocate(p); // speicher freigeben
    
    1. da objekte mit ctor in C++ immer dynamisch initialisiert werden braucht man einfach keinen eigenen const-ctor. wer mag kann ja beliebige parameter verwenden um dem ctor irgendetwas mitzuteilen, bzw. auch dummy-parameter um eine speziellen ctor zu wählen:
    struct my_const_tag {};
    class foo
    {
    public:
        foo(){}
        foo(my_const_tag){} // alternativer ctor
    };
    
    foo const f(my_const_tag());
    

    BTW: ich hatte noch NIE einen fall wo ich im ctor wissen wollte ob mein objekt const oder nicht const angelegt wird.

    1. wieso heisst ein fenster fenster und nicht susi?
      this ist ein pointer weil es eben ein pointer ist. gute gründe dafür kann ich dir nicht nennen. gegenfrage: wieso stört es dich denn?


    1. Vlt. weil sie als sie C++ erfunden haben noch zu sehr C dachten.

  • Mod

    frage 2: Das ist nur Spekulation, aber ich denke mal, dass man diese Unterscheidung nicht für nötig gehalten hat, es ist auch logisch fragwürdig - da dann const- und nicht-const-Objekte nicht austauschbar sind, hätten wir es eigentlich mit Objekten verschiedener Klassen zu tun (sofern eben const das Verhalten ändern, andernfalls wird die Unterscheidung überflüssig).
    Man kann allerdings trotzdem so etwas basteln:

    struct x {
      x(int, x&);
      x(int, const x&);
    // ggf. den SPass auch für den copy-ctor
    };
    ...
    x a = x( 0, a ); // die nicht-const Variante
    const x b = x( 0, b ); // die const Variante
    

    Zugegeben, das ist einer etwas dunkle Ecke der Sprache - aber ich kann ohnehin keinen echten Nutzen erkennen.

    frage 3:
    wieso ist this ein pointer? dafür gibt es keinen grund. this ist im prinzip für eine klasse x ein pointer vom typ

    x* const
    

    bzw

    const x* const
    

    . eine referenz ist genau das. initialisiert ist this auch immer automatisch. die semantik bezüglich const und non-const ist für pointer und referenzen die gleiche.

    Klassen, und damit auch this wurden so ziemlich als erstes der Sprache hinzugefügt, als C-with-classes entstanden ist. Referenzen gab es erst, als Operatorüberladung eingeführt wurde. Dann zu diesem Zeitpunkt noch den Typ von this zu ändern hätte zu Inkompatibilitäten mit existierendem Code geführt ohne irgendeinen Nutzen zu haben.
    Übrigends ist der Typ von this nicht
    cv T* const, sondern nur cv T*
    this ist ein rvalue (das war mal vor langer Zeit, als es noch Dinosaurier gab (vor ARM), anders: bevor new eingeführt wurde, konnte man this im Konstruktor zuweisen, um den Effekt von placement-new zu erreichen).



  • besserwisser schrieb:

    ...
    frage 2:
    const constructor.

    class x {
      x(void); // ok
      x(void) const; // nicht ok
    };
    

    ...

    Hmmm nunja, ich habe hier einmal gelernt, dass ein Konstruktor zwar syntaktisch an eine Memberfunktion angelehnt ist, aber nicht wirklich eine solche ist (was man allein schon daran sieht, dass man sie für ein konstruiertes Objekt nicht aufrufen kann)....

    Inhaltlich halte ich eine "const-Zusage" einer "Funktion", die ausschließlich im Rahmen der Erzeugung eines Objekts ausgeführt wird, für eher entbehrlich (vorsichtig formuliert). Ich wüsste nicht, wann/warum man sie sinnvoll einsetzen könnte.

    Gruß,

    Simon2.



  • camper schrieb:

    ...Referenzen gab es erst, als Operatorüberladung eingeführt wurde...

    Das ist interessant.
    Über den Zusammenhang hatte ich noch gar nicht nachgedacht.
    Aber "zwingend" war das nicht unbedingt, oder ? Hätte man operatoren nicht genauso "implizit" mit Zeigern definieren können, wie das z.B. mit der "impliziten Dereferenzierung" beim operator->() funktioniert ?
    Gab's noch andere Motivationen für Referenzen ?

    Gruß,

    Simon2.

    P.S.: Nicht, dass ich Referenzen missen wollte - ist nur Interesse.



  • camper baust du beruflich C++ Compiler?


  • Mod

    Simon2 schrieb:

    Hätte man operatoren nicht genauso "implizit" mit Zeigern definieren können, wie das z.B. mit der "impliziten Dereferenzierung" beim operator->() funktioniert ?

    Das wäre aber mehrdeutig bei Operatoren, die bereits mit zeigern zusammenarbeiten, davon gibt es ja eine ganze Menge. z.B.

    rational* normalize(rational*); // angenommen, wir machen alles irgendwie mit Zeigern
    
    rational f( 2, 4 );
    cout << ( normalize( &f ) + 5 ); // rational + 5 oder normale (hier sinnlose) Zeigeraddition?
    


  • 👍 Cooles Beispiel !!
    Danke,

    Simon2.



  • @hustbaer
    dieses placement delete ist mir bekannt. ich hätte es wohl anders beschrieben sollen. deine methode, das placement delete zu ersetzen, ist auch schon bekannt. die frage ist nur, wieso man das nicht in die sprache mitaufnimmt. es wäre problemlos mit der existierenden semantik des placement deletes vereinbar. placement new und delete sind nur für die allokation zuständig. ctor und dtor werden sowieso vom compiler erst nach bzw vor den placements ausgeführt. sollte bei placement new eine exception auftauchen, ist placement delete nach wie vor wie in der existierenden version verwendbar. sollte man das nicht in den neuen c++09 standard aufnehmen? hat das nie jemand dort zur sprache gebracht?

    ein beispiel dafür ist const_iterator. mit const konstruktoren wäre const_iterator nicht mehr nötig und man könnte nur mehr iterator verwenden. const_iterator ist nach wie vor ein workaround aufgrund der fehlenden const konstruktoren. die methode mit dummy parametern ist unelegant und ebenso ein workaround. außerdem ist es im iterator beispiel nicht verwendbar. im iterator ein bit für einen const iterator zu setzen und dann bei änderung eine exception zu werfen, ist ebenso unelegant, da damit ein problem, das zur compilierzeit erkannt werden könnte, zur laufwerk erst beachtet wird.

    was bedeutet "dynamisch initialisiert"? der datentyp und damit die const-ness ist zur compilierzeit festgelegt.

    das mit this stört mich nicht in dem sinn. es ist nur eine inkonsistenz des standards. ich führ etwas ein, verwende es aber dann nicht bei einem anderen feature, das ich ebenso eingeführt hab.

    @camper
    wobei unterscheidet sich this von der semantik von

    x* const
    

    ?
    leider habe ich so eine antwort erwartet. schade, dass man bei c++ derart konservativ ist, dass man die eigenen features nicht einbauen und fehler nicht korrigieren will. abwärtskompatiblität ist wirklich der tod jedes fortschritts und korrigierens von inkonsistenzen.

    ich hoffe, dass mich hier niemand falsch versteht. es geht mir nicht darum, zu nörgeln sondern um eine verbesserung von c++. ich kenne viele der neuerungen für c++09. viele erscheinen mir kopiert von anderen sprachen bzw eher eine art modeerscheinung (das ganze lambda zeug zb). existierende probleme wurden weniger beachtet. so kommt es mir halt vor.



  • zu 2.
    const bei Methoden gibt ja an, dass diese Methode nichts am objekt ändert. Und diese eigenschaft schließt sich in Kombination mit einem Konstruktor aus, der ja schon allein aus dem Grund ein Konstruktor zu sein das Objekt verändert. Also ist es vollkommen logisch, das es sowas nicht geben kann.

    zu 3.
    ob this nun ein Pointer oder eine Referenz ist, ist doch vollkommen egal, Intern ist es doch sowiso das selbe, nur die Schreibweise ist eine Andere.

    zu 1.
    Irgendwie verstehe ich die Frage nicht, ich hab auch noch nie was von einem placement delete gehört, was soll das sein, und wo ist der Unterschied zu einem normalem delete.



  • leider stimmt das nur halb. const bezüglich selbst definierter klassen ist nicht unbedingt das gleiche wie const an pods. man kann die semantik von const zu einem gewissen teil selbst bestimmten. ein iterator beispielsweise kann zwar const sein, was damit aber nicht bedeutet, dass sich die instanz nicht ändert. wäre das voraussetzung, wäre das keyword mutable nutzlos und ein konstanter iterator würde sich nie von der stelle bewegen. ich denke, dass es durchaus üblich ist, für eigene klassen auch eigene semantiken bezüglich const-ness zu definieren. const am iterator bedeutet, dass man die elemente, über die man iteriert, nicht ändern kann. iterator und const_iterator sind beispiele dafür.

    es geht nicht um egal oder nicht. die frage war, warum es so ist und das wurde beantwortet.

    placement new bedeutet, dass man new als operator überladen kann und dabei auch parameter übergeben kann. zb eine klasse, die speicher verwaltet. siehe mein beispiel. eine andere methode ist das placement new, bei dem ein speicherplatz als parameter (als pointer) an new direkt übergeben wird und der compiler nur mehr den ctor der klasse auf diesem speicherplatz ausführt. das führt übrigens zu einer standardkonformen methode, einen ctor explizit auf einem speicherplatz auszuführen. auch eine zweifelhafte inkonsistenz, da man den dtor direkt, ctors nur über das placement new ausführen kann.



  • ein const_iterator ist kein const iterator, da muss man utnerscheiden. ein const iterator kann tatsächlich nicht verändert werden, während ein const_iterator auf objekte zeigt die nicht verändert werden können.
    Was den Ctor angeht: Die Lebensdauer eines Objekts beginnt nach Ablauf seines Ctors, was bedeutet, dass das Objekt auch erst nach der vollständigen Konstruktion const oder non-const sein kann. Demzufolge gibts schon von der Semantik der Ctoren her keinen Unterschied zwischen Ctoren für const und non-const Objekte.



  • äh. huch?
    ein "const_iterator" entspricht einem "T const*".
    ein "iterator const" entspricht einem "T* const".

    wie also willst du mit deinem "const ctor" const_iterator überflüssig machen? oder willst du dass man einen "iterator const" weiterschieben kann? das wäre aber sowas von hässlich.

    bei der placement delete sache muss ich dir recht geben, wäre nicht doof wenn man den direkt aufrufen könnte. allerdings halte ich es andrerseits auch wieder für ziemlich egal, da ich für meinen teil selten bis nie mit placement new/delete arbeite.

    was mich da wesentlich mehr stört ist dass es auf einigen systemen (windows z.b.) so umständlich ist die new implementierung auszutauschen. das redefinieren des globalen operator ist zwar theoretisch möglich, praktisch aber nicht einsetzbar sobald man die DLL runtime verwendet. klar, das ist jetzt nicht die schuld des C++ standard, aber es passt für mich irgendwie zum thema.



  • pumuckl schrieb:

    Die Lebensdauer eines Objekts beginnt nach Ablauf seines Ctors, was bedeutet, dass das Objekt auch erst nach der vollständigen Konstruktion const oder non-const sein kann.

    über lebensdauer mag man diskutieren können. gehört ein ctor dazu oder nicht? das ist aber auch nicht wichtig. es geht hier nicht um lebensdauer sondern um den typ einer instanz. typ und const-ness werden gleichzeitig untrennbar bestimmt. und beides wird vor dem aufruf des ctors bestimmt. wenn dem nicht so wäre, könnte man ja nie den richtigen ctor aufrufen. dementsprchend kann man deinem argument zustimmen, es ist aber für die sache hier nicht relevant.

    @hustbaer
    du meinst also, dass ein const iterator nicht das gleiche ist wie ein const_iterator? da bin ich mir nicht sicher. ein const_iterator wird bei const instanzen verwendet. es gibt bei allen klassen verschiedene ebenen an const-ness. darf man die elemente einer konstanten liste ändern oder nicht? oder ist nur die liste als solche konstant, dh die anzahl der element und deren reihenfolge? braucht man einen const iterator in der art, dass man ihn nicht bewegen kann? ist das dann überhaupt sinnvoll? die hauptaufgabe eines iterators ist das iterieren, sodass ein unbeweglicher iterator relativ sinnlos ist. in meinen augen halt. aber wie bei der konstanten liste ist das sicher subjekt. beim iterator würde ich die konstantheit eher auf die element legen und nicht auf das bewegen. will ich einer funktion einen unbeweglichen iterator übergeben, kann ich gleich eine referenz auf das aktuelle element übergeben.

    das problem der prozessübergreifenden ersetzung von new und delete ist eher kompliziert. beim gcc sind beides funktionen der libgcc (bzw gcc_s), die man überschreiben könnte um dann die exe mit -export-dynamic zu compilieren. damit würden auch alle bibliotheken die new/delete funktionen der exe verwenden. wie das im windows geht, weiß ich nicht. bin kein windowsprogrammierer 🙂


  • Mod

    besserwisser schrieb:

    du meinst also, dass ein const iterator nicht das gleiche ist wie ein const_iterator? da bin ich mir nicht sicher. ein const_iterator wird bei const instanzen verwendet. es gibt bei allen klassen verschiedene ebenen an const-ness. darf man die elemente einer konstanten liste ändern oder nicht? oder ist nur die liste als solche konstant, dh die anzahl der element und deren reihenfolge? braucht man einen const iterator in der art, dass man ihn nicht bewegen kann? ist das dann überhaupt sinnvoll? die hauptaufgabe eines iterators ist das iterieren, sodass ein unbeweglicher iterator relativ sinnlos ist. in meinen augen halt. aber wie bei der konstanten liste ist das sicher subjekt. beim iterator würde ich die konstantheit eher auf die element legen und nicht auf das bewegen. will ich einer funktion einen unbeweglichen iterator übergeben, kann ich gleich eine referenz auf das aktuelle element übergeben.

    Bei einem Iterator kann man klar zwischen dem zeigenden Etwas (dem Iterator selbst) und dem Objekt, auf das gezeigt wird unterscheiden und natürlich können beide unabhängig const sein oder nicht. Nun ist es selbstverständlich denkbar, dass man const durchreicht - ein konstanter Iterator könnte beim Dereferenzieren auf ein konstantes Objekt zeigen. Man gewinnt dadurch nichts und es widerspricht dem Prinzip der geringsten Überraschung (weil eben Zeiger, als Grundmodell eines Iterators, dieses Verhalten nicht zeigen). Umgekehrt genügt auch unter dieser Bedingung die Konstanz des Iterators nicht, um Konstanz des Objektes, auf das gezeigt wird, zu garantieren. Warum? Weil uns nichts daran hindert, den konstanten Iterator einfach in einen nicht-konstanten Iterator zu kopieren und damit weiterzuarbeiten und die eigentlich konstante Sequenz doch noch zu verändern - so etwas darf nicht sein. Das Verhalten von const_iterator ist etwas ganz Anderes als des Verhalten iterator - und nicht bloß ein Modus seiner Funktionalität.

    Zu placement-delete kann ich nur spekulieren. Gezeigt wurde bisher kein Beispiel, in dem der konkrete Nutzen eines solchen Features evident wird. Placement new ist ein ganz anderer Fall: es gibt keine Möglichkeit, diese Funktionalität auf anderem Wege zu erhalten. Operator delete ist bereits eine recht interessante Funktion: wir können bekanntlich diese Funktion in einer Klasse überladen. Wenn nun eine Klasse polymorph ist, muss beim delete (intern vermittelt durch den virtuellen Destruktor) die entsprechende Überladung, die zum dynamischen Typ des ursprünglichen Objekts passt (beim eigentliche Aufruf ist das Objekt schon tot, wir haben es hier also mit einer Art "statisch-virtuellen" Funktion zu tun - ein sehr spezieller Fall), aufgerufen werden. Falls wir nun nun placement-delete-Überladungen zulassen (das ist bereits der Fall) und diese über eine entsprechende delete-Form aufrufen wollen, stoßen wir auf einige Probleme:
    1. Die betreffende placement-Form könnte in der Basisklasse fehlen (oder schlimmer: eine weniger gute placement-Form auswählen) - was tun? Auf gut Glück versuchen und im Zweifel mit einem Fehler aussteigen oder lieber gleich ill-formed machen?
    2. Die betreffende placement-Form könnte in der abgeleiteten Klasse verdeckt sein - wieder ein seltsamer Fall, dann können wir nur über die Basisklasse löschen.
    3. Der Destruktor der Basisklasse weiß nichts von Überladungen in abgeleiteten Klassen - er muss aber irgendwie in der Lage sein, mit diesen Überladungen zu kommunizieren, unabhängig von ihrer Signatur. Das ist prinzipiell machbar, aber kaum ohne Overhead: ein Totschlagargument, schließlich wollen wir nicht für Features bezahlen, die nicht genutzt werden und new/delete-Überladung ist bereits vergleichsweise selten.

    Es müsste
    1. ein hinreichender Nutzen demonstriert werden und
    2. die Machbarkeit einer Implementation, die bei Nichtnutzung ohne signifikanten Overhead auskommt, gezeigt werden und
    3. die Semantik in komplizierter Fällen (s.o. - das sind mit einiger Sicherheit nicht alle Probleme, die sich ergeben) geklärt werden,
    bevor man so etwas als Spracherweiterung in Angriff nehmen könnte.



  • Was sollte denn ein const-Ctor denn genau bewirken?
    a) Das Objekt soll während der Konstruktion nicht verändert werden. Das impliziert eigentlich nur, dass der Ctor Rumpf leer ist und alles bereits in der Initialisierungsliste geschieht. Außerdem gibt es das Objekt während der Konstruktion eben noch nicht (-> Lebensdauer), also hieße das, dass die Elemente des Objektes nach ihrer Initialisierung konstant bleiben. Der leere Ctor-Rumpf garantiert das, also ist dafür kein extra const-Ctor nötig.
    b) Das Objekt soll nach der Konstruktion konstant bleiben. Ob ein Objekt nach seiner Konstruktion verändert wird oder nicht, hat keinerlei Auswirkungen auf die Art, wie es konstruiert wird. Damit wäre diese Interpretation eines const-Ctors auch widersinnig.
    Ich lass mich gern eines besseren belehren, aber ich sehe keinen Nutzen für einen extra-Ctor für const Objekte.

    Was den const Iterator angeht: natürlich ist ein Objekt, dessen Zweck die Veränderung des eigenen Zustandes ist, das aber als const deklariert wird, von fragwürdigem Nutzen. Dennoch ist es ein legales Konstrukt. Den const_iterator zu verwerfen und statt dessen als const iterator zu bezeichnen ändert die Semantik des keywords const in der Sprache. Ein const bei einem Objekt bedeutet in der Sprache immer, dass das Objekt selbst seinen Zustand nicht ändert. Ein Objekt als const zu deklarieren obwohl es verändert werden kann, nur weil das Objekt auf das es verweist nicht verändert werden kann, würde die Semantik des keywords const für den Einzelfall verändern, was widerum garnicht gut ist.
    Was die const list angeht heißt const in erster Linie (Sprachsemantik) nur, dass die Liste selbst nicht verändert werden darf. Ob man das jetzt so interpretiert, dass die Elemente der liste nicht zur Liste selbt gehören (und damit verändert werden dürfen) oder nicht, ist Sache der Auslegung des Konzeptes einer Liste. in der STL gehören die Elemente eines Containers zum Container dazu, deshalb können die Elemente des Containers nicht verändert werden, wenn er const ist. Man kann sich aber durchaus implementationen vorstellen, wo die Liste nur als Liste von Verweisen interpretiert wird und die Elemente auf die verwiesen wird nicht zwangsläufig const sind. Bei so einer Implementation würde wahrscheinlich neben der list auch eine const_list angeboten analog zum const_iterator. Auch hier wäre eine const List (mit veränderbaren Elementen) nicht das selbe wie eine const_list (wo die Liste zwar ergänzt werden könnte, nicht aber ihre Elemente verändert). Dieses Komplizierte Bild ergibt sich hauptsächlich bei Objekten, die auf andere Objekte verweisen, wie eben iteratoren. Bei Zeigern bietet die Sprache zwei const-Möglichkeiten an, nämlich für den Zeiger selbst und für das referenzierte Objekt. Da etwas wie ein " const iterator const " aber nicht in die Sprache passt, muss man das const für die referenzierten Elemente irgendwo mit in den Typen packen:

    T       *         iterator              std::list<T>         //objekt und referee veränderbar
    T const *         const_iterator        std::list<const T>   //objekt veränderbar, referee const
    T       * const   const iterator         --- N/A ---         //objekt const, referee veränderbar
    T const * const   const const_iterator  const std::list<T>   //objekt und referee const
    


  • pumuckl schrieb:

    Was sollte denn ein const-Ctor denn genau bewirken?
    a) Das Objekt soll während der Konstruktion nicht verändert werden. Das impliziert eigentlich nur, dass der Ctor Rumpf leer ist und alles bereits in der Initialisierungsliste geschieht....

    Nicht unbedingt !

    struct Obj;
    struct ObjListe {
       vector<Obj*> objs;
    };
    
    struct Obj {
       Obj(ObjListe& ol) {   ol.objs.push_back(this); }
    };
    

    Mag man für tolles Design halten oder nicht, aber hier wird der Konstruktor sinnvoll und trotzdem nicht zur Veränderung des Objekts eingesetzt.

    Ich finde dabei viel wesentlicher, dass man (soweit mir einfällt) einen Konstruktorcall niemals in einem Zusammenhang auslösen kann, der einer const-Zusage für das betroffene Objekt gerecht wird.

    Gruß,

    Simon2.



  • @besserwisser:

    Ja, ein nicht verschiebbarer Iterator macht wenig Sinn. Allerdings halte ich die Idee die Bedeutung von "const" zu "redefinieren" nicht für gut. Wie camper schon geschrieben hat führt das zu Überraschungen. Stell dir vor du machst eine Liste aus Iteratoren die auf bestimmte Elemente eines Containers zeigen. Nun übergibst du eine const Referenz auf diese Liste an irgendeine Funktion. Diese Funktion könnte dann die Iteratoren in der Liste verschieben - trotz const Referenz. Nicht sehr intuitiv.

    beim gcc sind beides funktionen der libgcc (bzw gcc_s), die man überschreiben könnte um dann die exe mit -export-dynamic zu compilieren. damit würden auch alle bibliotheken die new/delete funktionen der exe verwenden. wie das im windows geht, weiß ich nicht. bin kein windowsprogrammierer 🙂

    Unter Windows geht das leider garnicht so einfach. Es fehlt nämlich das "-export-dynamic" Feature, bzw. sind DLLs unter Windows einfach ziemlich unterschiedlich zu SOs unter Linux. Das Problem ist dass die anderen DLLs sich nicht die Funktion "operator new, egal woher sie kommt" importieren, sondern genau angeben aus welcher DLL sie diesen "operator new" haben möchten. Man kann nun zwar hergehen und in der .exe einen eigenen "operator new" definieren, und diesen auch exportieren, allerdings wird ihn kein Code ausser dem in der .exe verwenden. Die "Lösung" ist die Runtime DLL nach dem Laden im Speicher zu patchen. Relativ "pfui" wenn du mich fragst 🙂



  • besserwisser schrieb:

    ...typ und const-ness werden gleichzeitig untrennbar bestimmt. und beides wird vor dem aufruf des ctors bestimmt...

    Das verstehe ich nicht. Nenn mal ein Beispiel ...
    Ich kenne "const" nur als Qualifier für einen Bezeichner (niemals als Eigenschaft einer Instanz). Und als solcher liefert er eine "Schnittstellenzusage" für diesen Bezeichner ("Über mich wird die Instanz nicht verändert") .... aber doch nicht über ein Objekt selbst.

    In die Falle war man bei unserem alten C-Compiler (Standard ?) schon gestolpert ... mit dem Erfolg, dass Folgendes nicht erlaubt war:

    f(char const* s);
    
    char text[100];
    strcpy(text, "Simon2");
    f(text); // "invalid type conversion from 'char*' to 'char const*'
    

    Was dem Verständnis von const eigentlich total zuwider läuft !
    Warum sollte es verboten sein, einer Funktion, die zusagt, die Übergabedaten nicht zu verändern, Daten zu übergeben, die das sogar zuließen ?

    Gruß,

    Simon2.



  • Also ein const-Ctor ist einfach Unsinn.
    Hier wird IMMER schreibend auf das (noch gar nicht wirklich existente Objekt) zugegriffen. Zumindest der this-Zeiger wird immer (implizit) angefasst, wenn das Objekt konstruiert wird. Insbesondere auch bei const-Objekten muss ja gerade der Konstruktor dafür sorgen, dass ein solches Objekt überhaupt definierte Werte bekommt. const-Methoden dürfen aber per Definition das Objekt nicht verändern. Das gilt für alle Konstanten. Sie sind zum Zeitpunkt ihrer Definition noch nicht Konstant. Sonst könnten sie gar nicht definiert werden.


Anmelden zum Antworten