object am stack anlegen unterbinden/erschweren



  • auf http://www.cpp-tutor.de/cpp/le12/ueberl_spez.html steht:

    Die Operatoren new und delete können für eine Klasse nur durch eine statische
     Memberfunktion überladen werden. Auch wenn die Memberfunktion nicht explizit
     als statisch deklariert wird, wird sie durch den Compiler immer als solche
     angelegt
    

    theoretisch muesste dann der operator new auf den privaten constructor
    zugreifen koennen. aber auch wenn das aus irgendeinem grund nicht der fall sein
    sollte koennte man das so machen:

    class test
    {
       public:
          int val;
    
          test(const test&) = delete;
          test(test&&) = delete;
    
          static test* create(void)
          {
             return new test(); 
          }
    
          void* operator new(size_t size)
          {
             return test::create();
          }
    
       private:
          test(void) : val(0) { }
    
       public:
          ~test(void) { }
    }; /* class test */
    

    test::create kann ja auf jeden fall ein object anlegen. aber so funktioniert
    das auch nicht

    error C2248: "test::test": Kein Zugriff auf private Member, dessen Deklaration
     in der test-Klasse erfolgte.
    1>          d:\nachtschatten\programming\gromit\gromit\main.cpp(36): Siehe 
    Deklaration von 'test::test'
    

    das versteh ich jetzt aber ueberhaupt nicht wo da das problem liegt.
    test::create ist schliesslich public.



  • Meep Meep schrieb:

    operator new

    Das ist der völlig falsche Ansatz. Overengineering, Overkill, den Nutzer bevormundend, etc.

    Technisch spricht sicher nichts dagegen, das auf dem Stack anzulegen (den entsprechenden Speicher kannst du ja intern auf den Heap legen). Die Lebensdauer bestimmt der Anwender. Vielleicht gibt es ja in irgend einem Umstand einen guten Grund, das in einer bestimmten Situation auf dem Stack anzulegen. Das dann zu verbieten wäre unnötig.

    Lass die Idee einfach fallen.

    Wenn Kopie keinen Sinn macht, lösche den Kopierkonstruktor/Kopierzuweisung. Wenn Move keinen Sinn macht, dann auch das. std::mutex ist z.B. nicht movable, aber lässt sich trotzdem auf dem Stack anlegen (und das ist auch oft gut so).

    Wenn das nicht genug ist, dann soll man das halt manuell auf dem Heap anlegen.


  • Mod

    Bitte vollständiges Minimalbeispiel!

    Und beantworte bitte Jockelxs Frage!



  • Einfache Lösung: Mach das Ding so groß, daß es bei den Standareinstellungen aller gänigen Compiler nicht mehr auf den Stack passt. 😃



  • Swordfish schrieb:

    Einfache Lösung: Mach das Ding so groß, daß es bei den Standareinstellungen aller gänigen Compiler nicht mehr auf den Stack passt. 😃

    😃

    class test
    {
       public:
          int val;
    
          test(const test&) = delete;
          test(test&&) = delete;
    
          static test* create(void)
          {
             return new test();
          }
    
          void* operator new(size_t size)
          {
             return test::create();
          }
    
       private:
          test(void) : val(0) { }
    
       public:
          ~test(void) { }
    }; /* class test */
    
    int main(void)
    {
       test *t1 = new test();
    }
    

    ich dachte das ich so mit dem ueberladenen new eine instanz erzeugen kann. aber
    ich denke mal das das problem hier die compilermagie ist, die den constructor
    selbst aufruft. new gibt ja eigendlich nur nen raw-speicher zurueck wenn ich
    das richtig verstanden habe. also wird es danmn nichts bringen wenn ich in
    operator new eine instanz der klasse erzeugen lasse, weil dann trotzdem
    irgendwie nochmals der constructor fuer den zurueckgegebene speicher aufgerufen
    werden wird und da kommt dann auch wieder das problem mit dem privaten
    constructor.

    ich werde es wohl mit dem privaten destructor machen

    Meep Meep



  • Jockelx schrieb:

    Und warum sorgen die Objekte nicht selber dafür, dass der grosse Teil auf'm Heap angelegt wird?

    wie schon gesagt gehoeren die klassen zu einem framework. die verbindung
    untereinander ist aehnlich wie bei einem baum. funktionieren auch zum teil als knotenklassen.
    die klassen verwalten sich hierbei selber. wenn ich einen knoten loesche dann loescht er zuerst alle objecte die unter sich sind. ich kann nun eigene objecte einfuegen. ob die nun auf dem stack oder am heap liegen ist da noch egal.
    das problem erfolgt dann bei der zerstoerung der objekte. ich muesste buchfuehren ob ein objekt am stack oder am heap erstellt worden ist. meines wissens gibt es keine moeglichkeit, das ohne weiteres rauszufinden.

    kurz um: es ist eine design entscheidung die ich nun mal gefaellt habe und die mir ansich gefaellt


  • Mod

    Meep Meep schrieb:

    wie schon gesagt gehoeren die klassen zu einem framework. die verbindung
    untereinander ist aehnlich wie bei einem baum. funktionieren auch zum teil als knotenklassen.
    die klassen verwalten sich hierbei selber. wenn ich einen knoten loesche dann loescht er zuerst alle objecte die unter sich sind. ich kann nun eigene objecte einfuegen. ob die nun auf dem stack oder am heap liegen ist da noch egal.
    das problem erfolgt dann bei der zerstoerung der objekte. ich muesste buchfuehren ob ein objekt am stack oder am heap erstellt worden ist. meines wissens gibt es keine moeglichkeit, das ohne weiteres rauszufinden.

    Also ein intrusiver Container? Da wäre es aber ein Fehler im Design, wenn der Container selber anfängt, Elemente zu löschen. Die Elemente einer intrusiven Datentstruktur gehören nicht der Datenstruktur, sondern die Datenstruktur ist aus diesen Objekten aufgebaut, die aber unabhängig von diesem existieren.



  • Meep Meep schrieb:

    ich kann nun eigene objecte einfuegen. ob die nun auf dem stack oder am heap liegen ist da noch egal.

    Nein, das ist nicht egal.

    Du verbietest einfach (in der Doku!) dass Objekte übergeben werden die am Stack liegen.
    Und als "dezenten aber schwer übersehbaten Hinweis" 🤡 lässt du die Ownership-übernehmenden Funktionen einen besitzenden Smart-Pointer (z.B. std::unique_ptr) als Parameter nehmen. => Problem gelöst.

    Wenn jmd. dann ausserhalb von diesem Anwendungsszenario eines dieser Objekte (z.B. den Rootknoten) auf den Stack legen will, dann soll er doch. Kann dir Schnuppe sein.



  • SeppJ schrieb:

    Die Elemente einer intrusiven Datentstruktur gehören nicht der Datenstruktur, sondern die Datenstruktur ist aus diesen Objekten aufgebaut, die aber unabhängig von diesem existieren.

    Naja, gibt solche und solche intrusive Container.
    Kann schon sinn machen einen besitzenden solchen zu haben.
    Wobei die Basis vermutlich erstmal immer ein nicht besitzender sein sollte. Denn da einen besitzenden draus zu machen ist dann ein 5-Zeiler oder so (mehr je nach Anzahl der Konstruktoren). Und umgekehrt geht's halt nicht (bzw. muss man die Containerklasse dazu umschreiben, was fies ist wenn man es nicht darf/kann).

    Als grundsätzlich sinnlos oder gar falsch würde ich besitzende Intrusive-Datenstrukturen aber nicht ansehen.



  • SeppJ schrieb:

    Meep Meep schrieb:

    wie schon gesagt gehoeren die klassen zu einem framework. die verbindung
    untereinander ist aehnlich wie bei einem baum. funktionieren auch zum teil als knotenklassen.
    die klassen verwalten sich hierbei selber. wenn ich einen knoten loesche dann
    loescht er zuerst alle objecte die unter sich sind. ich kann nun eigene objecte
    einfuegen. ob die nun auf dem stack oder am heap liegen ist da noch egal.
    das problem erfolgt dann bei der zerstoerung der objekte. ich muesste
    buchfuehren ob ein objekt am stack oder am heap erstellt worden ist. meines
    wissens gibt es keine moeglichkeit, das ohne weiteres rauszufinden.

    Also ein intrusiver Container? Da wäre es aber ein Fehler im Design,
    wenn der Container selber anfängt, Elemente zu löschen.

    mit intrusiver container kann ich jetzt gerade nicht viel anfangen. muss morgen
    mal nachlesen was das genau bedeutet.
    von alleine faengt da auch nichts an zu loeschen. ich selber bestimme wann und
    welches object geloescht wird. nur das ich mich dann nicht mehr um das loeschen
    bzw. freigeben der objekte kuemmern muss.
    ich werde mir ueber den ganzen ansatz nochmal den kopf zerbrechen. danke fuer
    die anregungen.

    Meep Meep


  • Mod

    Intrusive Container sind solche, die keine Kopien der Daten speichern, sondern bei dem direkt die Daten selber den Container aufbauen. Dazu müssen die Daten natürlich die benötigten Schnittstellen für die Verwaltungsdaten mitbringen, damit der Container aus den Daten seine Struktur bilden kann.
    Einer der großen Vorteile der Geschichte ist, dass der Anwender die Steuerung darüber hat, wo die Daten liegen, anstatt dass der Container sich über seinen Allocator wer weiß wo Speicherplatz besorgt. So kann der Anwender beispielsweise alle Elemente in ein Array packen und die Elemente dann an eine intrusive Liste geben und hat dann die Vorteile einer Listenstruktur, aber alles schön lokal beisammen!
    Der große Nachteil ist, dass der Container kein abgeschlossenes Objekt mehr ist, es liegt also eine deutlich höhere Verantwortung beim Benutzer, den Container richtig zu nutzen. Was du hier anscheinend mit Gewalt erzwingen möchtest, obwohl eine Dokumentation der richtigen Anwendung wohl auch reichen würde.

    Es gibt auch noch andere vor- und Nachteile, eine Übersicht und Einführung findest du hier:
    http://www.boost.org/doc/libs/1_57_0/doc/html/intrusive/intrusive_vs_nontrusive.html
    Deine Beschreibung klingt ganz so, als läge bei dir eine Art von intrusiver Container vor? Hast du den selber geschrieben? Oder benutzt du was fertiges? Falls ja, was?


Anmelden zum Antworten