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
databeim 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.
-
Bkann ich leider nicht ändern, weil ich vonstd::iostreamerbe und leider benötigt das einen Zeiger auf einenstd::streambuf.
denstd::streambufkann und will ich nicht kopierbar machen, was der Grund für die Zeigerhaltung ist.Beim Nachschauen, wie
boost::streamdas 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_ptrverwenden.Vielen Dank für deine Hilfe!