shared_ptr braucht vollständige Klassendefinition??



  • Servus,

    ich habe folgende Situation:

    class Derived;
    class Base {
    public:
        virtual ~Base(){}
        const Derived* foo() const { return foo_; }
        void setFoo(const Derived* foo) { foo_ = foo; }
    private:
        const Derived* foo_;
    };
    class Derived : public Base {
    public:
        virtual ~Derived(){}
    };
    

    Einige Base-Objekte halten ein Derived-Objekt, andere dort einfach einen Null-Pointer.
    Jetzt wollte ich mir die Mühe sparen, den Copy-Ctor und den Move-Ctor für Base zu schreiben, sondern das vom Compiler erledigen zu lassen. Also wollte ich aus dem dummen Pointer einen shared_ptr machen, und damit definiertes Kopierverhalten und korrekte Destruktion bekommen.

    Geht nur leider nicht, da ich folgenden Compilerfehler von gcc vor die Füße geworfen bekomme:

    /usr/local/include/boost/checked_delete.hpp:31: error: invalid application of 'sizeof' to incomplete type 'const Derived' 
    usr/local/include/boost/checked_delete.hpp:31: error: creating array with negative size ('-0x00000000000000001')
    

    Ich gehe mal stark davon aus, dass das daran liegt, dass er von Derived nur die Forward-Deklaration und nicht die Definition gesehen hat.

    Wie löst man diesen Widerspruch? Ich kann ja Derived nicht vor Base definieren.

    Gruß,
    Philipp

    EDIT: Kopierfehler im ersten Listing. Mit shared_ptr wird daraus:

    class Derived;
    class Base {
    public:
        virtual ~Base(){}
        const Derived* foo() const { return foo_.get(); }
        void setFoo(const Derived* foo) { foo_.reset(foo); }
    private:
        boost::shared_ptr<Derived const> foo_;
    };
    class Derived : public Base {
    public:
        virtual ~Derived(){}
    };
    

  • Mod

    Ich sehe hier keinen shared_ptr und Derived ist auch keine abgeleitete Klasse.



  • Okay, hab das Problem jetzt anders gelöst.
    Einsicht: Dass es Base-Objekte gibt, wo foo_ ein Nullpointer ist, und solche, wo foo_ auf eine Derived-Objekt zeigt, ist ein Scheißkonzept. Jetzt gibt's zwei Klassen, und zwar solche ohne foo_ member und solche mit.
    Damit entfällt der Bedarf für einen pointer an der Stelle vollkommen.

    Was mir allerdings immer noch nicht klar ist, warum boost::shared_ptr die Forward-Deklarierte Klasse angeblich nicht löschen können will.

    Denn die Boost Doku sagt ganz klar:

    Note that scoped_ptr requires that T be a complete type at destruction time, but shared_ptr does not.

    Siehe http://www.boost.org/doc/libs/1_49_0/libs/smart_ptr/smart_ptr.htm



  • Dem Destruktor ist das egal. shared_ptr::reset nicht! Lass dir doch gleich einen shared_ptr geben statt eines rohen Zeigers.



  • Bei shared_ptr::reset wird der shared_ptr mit nem neuen Objekt sowie einem neuen Deleter "befüllt".

    Um den Deleter "sicher" erzeugen zu können, zu erzeugen muss die Klasse vollständig definiert sein. Daher verwendet shared_ptr checked_delete, und sicherzustellen dass das auch so ist (C++ erlaubt ein delete auf unvollständige Typen, fordert dann aber dass diese trivial zerstörbar sind, was die meisten Klassen halt nicht sind).

    Du kannst aber jederzeit selbst einen eigenen Deleter mitgeben, dann wird dieser verwendet, und shared_ptr moppelt nicht mehr rum wegen Type nicht vollständig.


Anmelden zum Antworten