std::vector<std::uniqe_ptr<Class>>
-
Hey Leute,
ich arbeite an einem Projekt in dem ich dynamisch generierte Objekte in einem Vector speicher möchte. Ich möchte aber keine Ptr* benutzen, da ich schon oft gehört habe, dass diese eraltet sind und nicht mehr gerne gesehen werden.
class ClickerManager { public: std::vector<std::unique_ptr<obj::Clicker>> mClicker; ClickerManager(); ClickerManager(const ClickerManager &); virtual ~ClickerManager(); //Getter const std::vector<std::unique_ptr<obj::Clicker>> & getClickerVec()const; std::unique_ptr<obj::Clicker> getClickerPos(unsigned int pos); //Setter void addClicker(std::unique_ptr<obj::Clicker>& nClick); };
Hier nun die Implementierung
std::unique_ptr<obj::Clicker> ClickerManager::getClickerPos(unsigned int pos) { if(pos < mClicker.size()) { auto tmp = mClicker.at(pos); return tmp; } }
Hier spuckt der Compiler folgendes aus:
unique_ptr::unique::ptr(const unique_ptr &) is deleted
sowie
gelöschte Funktion »std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = obj::Clicker; _Dp = std::default_delete<obj::Clicker>]« wird verwendet auto tmp = mClicker.at(pos);
Was soll mir dieser Fehler sagen?
crsf1re
-
crsf1re schrieb:
Ich möchte aber keine Ptr* benutzen, da ich schon oft gehört habe, dass diese eraltet sind und nicht mehr gerne gesehen werden.
Hallo,
so ist die Aussage schlicht falsch. "Owning raw pointer" (also Zeiger, die Besitzer des Objekts sind), sind zurecht nicht gerne gesehen.
crsf1re schrieb:
gelöschte Funktion »std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = obj::Clicker; _Dp = std::default_deleteobj::Clicker]« wird verwendet
auto tmp = mClicker.at(pos);Was soll mir dieser Fehler sagen?
Deine Funktion kopiert den unique_ptr. Das darf sie aber nicht, weil es blöd wäre, weil ein unique_ptr ja gerade aussagt, dass es nur einen Besitzer geben darf.
Alternative:
Brauchst du Pointer? Ist Clicker eine Basisklasse und dein "dynamisch" heisst, dass verschiedene Ableitungen in den Container kommen?
Falls nicht, keine Pointer.
Falls du Pointer brauchst, dann lass die unique_ptr als member, gib aber einen raw-pointer zurück.
Wie gesagt, da ist überhaupt nichts schlecht dran; im Gegenteil: der Nutzer sieht sofort, dass ihm nicht gehört, was er da kriegt.
Oder gib (wie üblich bei gettern) eine const referenz zurück.
-
crsf1re schrieb:
ich arbeite an einem Projekt in dem ich dynamisch generierte Objekte in einem Vector speicher möchte. Ich möchte aber keine Ptr* benutzen, da ich schon oft gehört habe, dass diese eraltet sind und nicht mehr gerne gesehen werden.
Also erstmal bezieht sich das verpönt sein nur auf besitzende Zeiger, nicht auf Zeiger generell.
Dann noch gleich eine Frage hinterher: die dyanmisch generierten Objekte sind aber nicht alle vom selben Typ, sondern da sind obj::Clicker und Erben von obj::Clicker drin? Wenn nicht, wäre auch ein einfacher vector ausreichend.
crsf1re schrieb:
class ClickerManager { public: ClickerManager(); ClickerManager(const ClickerManager &); virtual ~ClickerManager();
Was soll der ClickerManager denn machen? Soll man von ihm erben können? Und vor allem: was soll mit den verwalteten Objekten vom Typ obj::Clicker geschehen, wenn du den ClickerManager kopierst? Soll es überhaupt 2 Manager geben dürfen? Dürfen clicker-Objekte mehreren Managern gehören?
Denn irgendwas wirst du dir ja mit dem Kopierkonstruktor und dem virtuellen Destruktor gedacht haben...crsf1re schrieb:
//Getter const std::vector<std::unique_ptr<obj::Clicker>> & getClickerVec()const; std::unique_ptr<obj::Clicker> getClickerPos(unsigned int pos); //Setter void addClicker(std::unique_ptr<obj::Clicker>& nClick); };
Getter, die dann die gesamte interne Darstellung rausgeben, sind immer erstmal fragwürdig, finde ich. Mit anderen Worten: brauchst du das getClickerVec wirklich?
Nun kommen wir zu deinem Problem: was soll denn das getClickerPos tun? Etwas, das get heißt, sollte doch zuallererst mal das Objekt selbst nicht ändern. Willst du den clicker also entfernen, wenn du getClickerPos aufrufst? Soll das Objekt kopiert werden? Oder willst du vielleicht nur ein
obj::Clicker*
zurückgeben (und der Besitz verbleibt bei dem Manager)?Generell ist eine Funktion, die einen unique_ptr zurückgibt, eine Quelle, d.h. sie gibt dem Aufrufer ein Objekt, das dann dem Aufrufer gehört.
Dein "Setter" addClicker (finde ich auch nicht, dass das ein Setter ist) ist dagegen ein ganz merkwürdiges Konstrukt. Eine Referenz auf einen unique_ptr als Parameter? Was soll das?
Vielleicht schaust du dir auch mal https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/ und https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-smartptrparam an.
PS: mach dir zu all meinem Fragen mal Gedanken. Sie sind primär dazu gedacht, dass DU darüber nachdenkst; ich stelle sie nicht, weil es mich brennend interessiert