Probleme mit Copy ctor
-
Hi,
ich habe folgendes Ojbektclass MathSubject { public: MathSubject(BaseMathObject *obj); template <typename Observer> void registerObserver(Events event, Observer &obs); void notify(Events event); BaseMathObject* getObject(); ~MathSubject(); private: BaseMathObject* data; std::map<Events, std::vector<std::function<void()>>>observers; };
Wie muss hier ein Kopierkonstruktor aussehen?
Alle versuche von mir sind fehlgeschlagen. Das Hauptproblem ist das polymorphe Memberdata
, da dieses beim kopieren verloren geht.Es geht darum das
MathSubject
in einem std::vector zu speichern.
Evtl. gibt es ja eine Möglichkeit ganz ohne Kopierkonstruktor?
-
Hi,
erstmal, gibt es einen Grund dafür, dass data ein Raw Pointer ist?
Wenn du smart Pointer verwenden würdest, würde sich das Problem quasi von alleine lösen. Mit einem unique_ptr gäbe es kein Copy Konstruktor und mit einem shared_ptr würde es der Default Ctor erledigen.
Ansonsten musst du wohl eine "Deep Copy" von Hand machen. z.B. so:
MathSubject(const MathSubject& obj): observers(obj.observers){ data = new BaseMathObject(); *data = *obj.data; }
Edit: Ich sehe grade, BaseMathObject ist polymorph. Dann schau doch mal hier: https://stackoverflow.com/questions/5148706/copying-a-polymorphic-object-in-c
-
Tatsächlich löst der shared_ptr das ganze Problem.
Danke!
-
Was macht denn der Destruktor eigentlich? Ruft der
delete data;
? Ich nehme mal an, dass er das tut. Dann wäre der Typ vondata
schon falsch. Er müsstestd::unique_ptr<BaseMathObject>
und nichtBaseMathObject*
sein. Und dann brauchst Du fürMathSubject
den Destruktor nicht selbst definieren. Und Du brauchst auch keine anderen der "special member functions" (kopierkonstruktor, zuweisungsoperator) definieren. Das Ding sollte dann automatisch "move-bar" sein und damit schon in einenvector
passen. Aufgepasst: Die Quell-Objekte eines moves sind dann unbrauchbar (Nullzeiger als data).Was die Kopiersemantik bei der Klasse sein soll, weiß ich nicht. Soll die map mit den Observers wirklich kopierbar sein? Falls das polymorphe Objekt mitkopiert werden soll, kanst Du da noch eine clone-Methode dranhängen. Also etwa so:
class BaseMathObject { public: virtual ~BaseMathObject() {} virtual void foo() const = 0; virtual void bar() = 0; virtual BaseMathObject* clone() const = 0; };
Und dann so:
class MathSubject { public: explicit MathSubject(std::unique_ptr<BaseMathObject> obj); MathSubject(MathSubject const& x) : data(x.data->clone()) , observers(...) // ? keine Ahnung, was hier die Kopiersemantik sein soll {} MathSubject(MathSubject && x) noexcept = default; MathSubject& operator=(MathSubject temp) { using std::swap; swap(this->data, temp.data); swap(this->observers, temp.observers); return *this; } template <typename Observer> void registerObserver(Events event, Observer &obs); void notify(Events event); BaseMathObject & getObject() { return *data; } BaseMathObject const& getObject() const { return *data; } private: std::unique_ptr<BaseMathObject> data; std::map<Events, std::vector<std::function<void()>>>observers; };
-
axels. schrieb:
Tatsächlich löst der shared_ptr das ganze Problem.
Danke!Das kann man ja nicht riechen. Du musst Dir schon selbst überlegen, ob das Ding kopierbar sein muss, und wenn ja, was da eigentlich passieren soll.
Ich möchte nochmal drauf hinweisen, dass Kopierbarkeit mein Muss ist, um es in einen vector stecken zu können. Ein Move-Konstruktor reicht auch schon.
-
axels. schrieb:
Tatsächlich löst der shared_ptr das ganze Problem.
Danke!Wahrscheinlich übertüncht er es nur.
Sollen tatsächlich zwei Objekte das gleiche data-Objekt referenzieren?
MathSubject(BaseMathObject *obj);
Input ist ein Raw Pointer und das Objekt fühlt sich dann fürs Löschen verantwortlich? Das stinkt.