Wie könnte man new und delete auf einen Klassenzeiger verbieten



  • weicher schrieb:

    Warum willst du new verbieten?

    weil eine mit new erstellte Instanz nicht automatisch in ObjDB gespeichert wird.

    Warum nicht? Sowas sollte nach Möglichkeit in den Konstruktor der Basisklasse.

    Das ist eigentlich genau das was ich suche.

    Findest du? Klingt für mich nach einer sehr umständlichen Lösung. Es reicht völlig aus, new und delete für deine Basisklasse private zu machen und CreateObj zum friend. Das Umgehen mit Placement New ist dann auch nicht möglich, weil ein operator new reicht, dass der Compiler nicht mehr die globalen op new in Betracht zieht - also auch kein Placement New.

    Aber es Hilft wohl nichts, ich muss wahrscheinlich das ganze Buch durcharbeiten ausser jemand erbarmt sich und nennt mir die Tipps die mir bei der Lösung helfen könnten.

    Selbst wenn sich jemand erbarmt, kommst du um das Buch nicht herum. Das Buch (und andere), bzw. der Inhalt sind für ein gutes C++ Sprachverständnis ein absolutes Muss.



  • Das ganze stellt ein Framework für Maschinensteuerungen dar. Da sind die realen Objekte auf der Maschine festgeschraubt, es macht also keinen Sinn während der Laufzeit des Programms Objekte hinzuzufügen oder zu zerstören.

    Dafuer gibt es viele Moeglichkeiten. Eine beispielsweise ist static . Klassen, die Arbeit an das eigentliche "Device" delegieren, eine andere.

    Kann man sowas irgendwie machen, oder muss ich mich nach wie vor auf die Disziplin meiner Kollegen verlassen?

    C++ is not a security device. Und warum sollte man sich nicht auf die Kollegen verlassen, wenn dieses Verhalten explizit dokumentiert und nachschlagbar ist?



  • weicher schrieb:

    - Alle Instanzen der abgeleiteten Klassen werden in ObjDB gespeichert.
    [...]
    - ObjDB löscht beim beenden der Applikation alle Objekte

    Die beiden Anforderungen implizieren, dass Stack-Objekte nicht erlaubt sind. Die Einwände gegen private Konstruktoren und Destruktoren fallen damit weg, wenn ich das richtig sehe.

    Das ganze stellt ein Framework für Maschinensteuerungen dar. Da sind die realen Objekte auf der Maschine festgeschraubt, es macht also keinen Sinn während der Laufzeit des Programms Objekte hinzuzufügen oder zu zerstören.

    Die Argumentation verstehe ich nicht. Kann die Maschine nicht umkonfiguriert werden? So dass zum Beispiel die Objekte nach Programmstart -- also zur Laufzeit -- nach den Einträgen in einer Konfigurationsdatei o.ä. erzeugt werden.

    knivil schrieb:

    Und warum sollte man sich nicht auf die Kollegen verlassen, wenn dieses Verhalten explizit dokumentiert und nachschlagbar ist?

    Weil Kollegen Schweinehunde sind 😉 Wenn da erstmal einer drei Wochen lang irgendwas gefrickelt hat und alles funktioniert, wirst du wohl keinen Projektleiter finden, der auf deinen Einwand hin eine riskante Umstrukturierung beauftragt. Schau dir Java an, welches dieses Prinzip perfektioniert hat. Eine solche Sprache ist genau deshalb für große Projekte mit vielen Mitarbeitern unterschiedlicher Qualifikationslevel geeignet, weil sie automatisch gewisse Standards erzwingt, ohne auf die Disziplin der Projektteilnehmer angewiesen zu sein.

    C++ is not a security device.

    Wo siehst du hier einen Zusammenhang zu Security? Hanlon's Razor!



  • Hallo dot,

    Fassen wir zusammen:
    Anzahl und Typ der Objekte ist bekannt und zur Laufzeit konstant.
    Die Objekte sollen die selbe Lebensdauer haben wie das ObjDB Objekt.

    Das stimmt! Aber nur genau für einen Maschinentyp.

    Sinn der Bibliothek ist es aber, alle möglichen Maschinentypen möglichst Komfortabel aufbauen zu können und nicht immer wieder bei null zu beginnen.

    Mit meiner Bibliothek kann man mit einem Wizard das Grundgerüst für eine neue Maschine erstellen. Die so erstellte Applikation hat bereits die Funktionen welche jede Maschine haben muss (Create, Init, Config; Setup, Manual, Automat).

    Die Bibliothek stellt auch Klassen für häufig benötigte Elemente zur Verfügung. Diese kann man im Eventhandler CreateObjects () mit CreateObj<classType>() erzeugen ("Probe", "XY-Table", "Laser", "MeasSystem" usw.).

    Herzliche Grüsse
    Walter



  • Wäre es nicht vielleicht sinnvoller, jeden Maschinentyp auch durch einen eigenen Typ im Programm zu repräsentieren?
    Schau dir vielleicht auch mal das Builder-Pattern an.



  • pumuckl schrieb:

    Das Umgehen mit Placement New ist dann auch nicht möglich, weil ein operator new reicht, dass der Compiler nicht mehr die globalen op new in Betracht zieht - also auch kein Placement New.

    Bei mir geht das.

    class Test
    {
        void *operator new(size_t size)
        {
            return ::operator new(size);
        }
    
        void operator delete(void *ptr)
        {
            ::operator delete(ptr);
        }
    
        public:
    };
    
    int main()
    {
        Test *c = static_cast<Test*>(malloc(sizeof(Test)));
        c = ::new(c) Test;
        c->~Test();
        free(c);
    }
    


  • Hallo zusammen,

    die Bibliothek ist ziemlich umfangreich, es ist schlicht illusorisch das ganze Konzept über den Haufen zu werfen da:
    - die Bibliothek sehr einfach zu benutzen ist.
    - viele Maschinen bereits Mithilfe dieser Bibliothek erstellt wurden
    - fast alle Konzepte von Scott Meyers erfüllt sind. Ich hatte beim lesen fast bei jedem Tipp ein Deja Vu 😉
    - das kein Mensch bezahlen kann und will.

    Es geht wirklich nur darum meine Objekt Pointer sicher zu machen.

    Der Aufwand muss sich aber in Grenzen halten da ich das aus finanziellen Gründen komplett in meiner Freizeit machen muss.

    Ich glaube ich schau mir mal die Tipps 17, 49..52 nochmal genauer an, eventuell könnten die weiterhelfen.

    Herzliche Grüsse
    Walter



  • wxSkip schrieb:

    Bei mir geht das.

    Mit explizit qualifiziertem globalem new, ja. Aber irgendwo ist dann auch wirklich mal die Grenze zum mutwillig destruktiven Verhalten überschritten - Scheiße bauen kann man immer, z.B. einfach memset auf ein beliebiges Objekt 😉


  • Mod

    pumuckl schrieb:

    wxSkip schrieb:

    Bei mir geht das.

    Mit explizit qualifiziertem globalem new, ja. Aber irgendwo ist dann auch wirklich mal die Grenze zum mutwillig destruktiven Verhalten überschritten - Scheiße bauen kann man immer, z.B. einfach memset auf ein beliebiges Objekt 😉

    Zumindest in generischem Code wäre das durchaus normal. Schließlich kann man sich kaum darauf verlassen, dass bei überladenem new-Operator auch an placement-new gedacht wurde. Beispielsweise ist das Verhalten der construct-Funktion des Standard-Allokator auch mit

    template <class U, class... Args>
    void construct(U* p, Args&&... args);
    12 Effects: ::new((void *)p) U(std::forward<Args>(args)...)
    

    beschrieben.



  • Wie wäre es mit:

    class SaveRootPtr {
       private:
           Root *ptr;
           SaveRootPtr(Root *r): ptr(r) {}
           ~SaveRootPtr() {}
       public:
           // Operator -> und * überladen (habe gerade keine Ahnung wie das geht xD)
           //...
       template <class ObjectType>
       friend SaveRootPtr CreateObject();
    };
    

    Und in createObject dann:

    Root *r=new T();
    return SaveRootPtr(r);
    

    Die Methoden der ObjDB Klasse bekommen dann ein SaveRootPtr als Argument.
    So kann niemand Objekte ohne die createObject Methode erstellen.



  • Ich hab' jetzt nicht alle Antworten gelesen, aber...

    Was spricht nun wirklich dagegen die Konstruktoren und Destruktoren private zu machen?
    Die Factory-Funktion muss irgendwie Zugriff auf Konstruktor und Destruktor haben, aber das lässt sich ja einrichten (z.B. mittels "friend").

    Wenn alle Objekte sowieso zu einem bestimmten Zeitpunkt zerstört werden sollen, und keine Shared-Ownership nötig ist, dann kann man weiterhin einfach mit rohen Zeigern arbeiten.
    new/delete funktionieren dann nimmer, und wenn keine Notwendigkeit besteht manuell new oder delete zu machen, und auch keine das "automatische delete" bei Programmende irgendwie verzögern zu können... dann sollte das doch damit gegessen sein. Oder übersehe ich was?

    p.S.: Die Konstruktoren/Destruktoren der Basisklassen müssen natürlich "protected" gemacht werden statt private. Oder aber die Basisklasse müsste alle abgeleiteten Klassen "kennen", was ... naja etwas komisch wäre.



  • Hallo hustbaer,

    Was spricht nun wirklich dagegen die Konstruktoren und Destruktoren private zu machen?

    Wie Du im PS sagts, geht's nur wenn die ctors und dtors in den Basisklassen nicht privat sondern protected sind.

    Das Bedeutet, die neue Regel lautet "bei allen Instanzierbaren Klassen müssen ctor und dtor Privat sein". Damit habe ich nur die alte Regel "Objekte dürfen nur mit CreateObj() erzeugt und nie mit delete gelöscht werden" mit einer neuen Regel ausgetauscht.

    Rein Gefühlsmässig ist der Verstoss gegen die neue Regel IMHO wahrscheinlicher 😉

    Herzliche Grüsse
    Walter



  • Wenn Du du eine Bibliothek nur für Deppen programmierst, mußt Du Dich nicht wundern, wer sie später nur benutzt.



  • weicher schrieb:

    Hallo hustbaer,

    Was spricht nun wirklich dagegen die Konstruktoren und Destruktoren private zu machen?

    Wie Du im PS sagts, geht's nur wenn die ctors und dtors in den Basisklassen nicht privat sondern protected sind.

    Das Bedeutet, die neue Regel lautet "bei allen Instanzierbaren Klassen müssen ctor und dtor Privat sein". Damit habe ich nur die alte Regel "Objekte dürfen nur mit CreateObj() erzeugt und nie mit delete gelöscht werden" mit einer neuen Regel ausgetauscht.

    Rein Gefühlsmässig ist der Verstoss gegen die neue Regel IMHO wahrscheinlicher 😉

    Herzliche Grüsse
    Walter

    Was willst du jetzt eigentlich damit sagen?
    Soll der Benutzer Stack-Objekte erstellen können? Wenn ja, was spricht dann gegen ein privates new und delete?

    EDIT: Meinst du damit, deine Kollegen würden sich nicht daran halten, Konstruktoren/Destruktoren bei neuen Klassen private/protected zu machen? Das kann man aber relativ einfach nachkorrigieren.



  • weicher schrieb:

    Was spricht nun wirklich dagegen die Konstruktoren und Destruktoren private zu machen?

    Wie Du im PS sagts, geht's nur wenn die ctors und dtors in den Basisklassen nicht privat sondern protected sind.

    Das Bedeutet, die neue Regel lautet "bei allen Instanzierbaren Klassen müssen ctor und dtor Privat sein". Damit habe ich nur die alte Regel "Objekte dürfen nur mit CreateObj() erzeugt und nie mit delete gelöscht werden" mit einer neuen Regel ausgetauscht.

    Rein Gefühlsmässig ist der Verstoss gegen die neue Regel IMHO wahrscheinlicher 😉

    Normalerweise werden seltener eigene Klassen definiert, als irgendwo Objekte erstellt werden.

    Wenn du aber wirklich etwas suchst was automatisch neue abgeleitete Klassen schützt, fürchte ich, kann ich dir nicht helfen. Sowas gibt's in C++ nicht.



  • class Base
    {
       protected:
          struct ErbenMuessenDenKonstruktorProtectedMachen
          {
          };
          Base(ErbenMuessenDenKonstruktorProtectedMachen,...)
          {
             ...
          }
    }
    

Anmelden zum Antworten