Basisklasse mit Membervariable initialisieren



  • Ich habe folgendes Problem:

    // vorgegeben                                                                   
    struct S { int da; bool ta; };
    class B {
    public:
      B(S *data) { /* ... */ }
    };
    
    // von mir geschrieben                                                          
    S *create_data(std::string s) { /* komplexe Initialisierung... */ }
    class D : public B {
    public:
      D(std::string s) : B((data = create_data(s))) {}
    private:
      S *data;
    };
    

    Klappt alles wie erwüscht. Nun aber möchte ich Pointer vermeiden und an der Stelle Smartpointer einsetzen.

    Mein Wunsch:

    std::tr1::shared_ptr<S> create_data(std::string s) { /* ... */ }
    class D : public B {
    public:
      D(std::string s) : data(create_data(s)), B(data.get()) {}
    private:
      std::tr1::shared_ptr<S> data;
    };
    

    Laut Standard muss die Basisklasse zuerst initialisiert werden, dass data beim Aufruf des Basisklassenkonstruktors undefiniert ist, erstaunt mich daher nicht. Aber so funktioniert das auch nicht:

    std::tr1::shared_ptr<S> create_data(std::string s) { /* ... */ }
    class D : public B {
    public:
      D(std::string s) : B((data = create_data(s)).get()) {}
    private:
      std::tr1::shared_ptr<S> data;
    };
    

    Ich erhalte dabei einen Speicherzugriffsfehler.

    Ist es möglich, das auf elegante Art mithilfe von std::tr1::shared_ptr<> zu lösen?



  • Benutze wenn, dann überall shared_ptr. Auch in B

    class B {
    public:
      B(const shared_ptr<S> data) { /* ... */ }
    };
    

    Dafür ist der shared_ptr ja da.

    class D : public B
    {
    public:
      D(shared_ptr<S> s) : B(s), s_(s) {}
      static D FromText(const std::string& s)
      {
         return D(create_data(s));
      }
    private:
      shared_ptr<S> s_;
    };
    

    Was aber ist überhaupt der Grund dafür, das S über einen Zeiger zu halten.



  • B kann ich leider nicht ändern, weil ich von std::iostream erbe und leider benötigt das einen Zeiger auf einen std::streambuf .
    den std::streambuf kann und will ich nicht kopierbar machen, was der Grund für die Zeigerhaltung ist.

    Beim Nachschauen, wie boost::stream das macht, bin ich auf das Boost: Base-from-Member Idiom gestossen. Der Name " member " sieht zwar etwas komisch aus, aber damit bin ich jetzt zufrieden. Scheinbar gibt es keine bessere Lösung für mein Problem.

    Der shared_ptr ist wirklich fehl am Platz, da hast du Recht. Mit den C++0x-Erweiterungen bin ich auf folgende, mich zufriedenstellende Lösung gekommen:

    S *create_data(std::string s) { /* ... */ }
    class D : private boost::base_from_member<std::unique_ptr<S>>, public B {
    public:
      D(std::string s) : boost::base_from_member<std::unique_ptr<S>>(create_data(s)), B(member.get()) {}
    };
    

    Ohne C++0x muss ich wohl den boost::scoped_ptr verwenden.

    Vielen Dank für deine Hilfe!


Anmelden zum Antworten