Basisklasse und abgeleitete Klassen in std::vector
-
Frage C++ schrieb:
Ich möchte einen std::vector<Basisklasse> vBK welchen ich mit abgeleiteten Objekten füllen kann,
Das ist ein Widerspruch!
Frage C++ schrieb:
...
Nun würde mich erstmal eine Erklärung zu oben beschriebenem interessieren und ob ich da einen Denkfehler drinnen habe.Das ist korrekt so.
Frage C++ schrieb:
Und dann zum zweiten Punkt. Wie realisiere ich es nun am besten, in einem vector vom Typ Basisklasse auch Subklassen unterzubringen. Mit Zeigern? Ist wieder umständlich wegen dem new/delete.
Mit Zeigern oder so etwas ähnlichem wie Zeiger. Wie sonst?
Frage C++ schrieb:
Lasst mal hören wie ihr das löst. Bitte um Lösungen die mit C++ und der STL auskommen.
Kommt echt drauf an. Neulich hab ich's so gemacht:
class PolymorphicBase { public: virtual ~PolymorphicBase() {} und so weiter }; und so weiter boost::ptr_vector<PolymorphicBase> vec; vec.push_back(new Derived("bla",23.0,42));Du kannst aber auch in C++11 'nen vector mit unique_ptr-Objekten befüllen...
-
cooky451 schrieb ironisch:
> Es ist so schlimm. Rohe besitzende Pointer sind das Böse. [...]
Jain. Je kleiner der Rahmen, desto besser und fehlerunanfälliger. Z.B. innerhalb eines
unique_ptrs oderptr_vectors geht's ja nicht anders. ^^ Und sonst sehe ich aber auch nicht wirklich einen Sinn darin, boost::ptr_vector nachzubauen ...
-
Das war nicht wirklich ironisch gemeint. Mit rohen Zeigern meinte ich natürlich alles außerhalb einer Smartpointer(-ähnlichen) Klasse.

Und nicht, wie viele vielleicht vermuten mögen, weil man das vergessen könnte. Nein, da muss man zwar drauf achten, aber es gibt viel schlimmere Dinge:
void foo() { A* a = new A; bar(); // BAM, Exception, Fail. delete a; }class C { A* a_; public: C() : a_(new A) { bar(); // BAM, Exception, Fail. } ~C() { delete a_; } };Deswegen halte ich es tatsächlich für grundsätzlich nicht vertretbar, besitzende Zeiger außerhalb von Smartpointern zu halten.
-
krümelkacker schrieb:
Und sonst sehe ich aber auch nicht wirklich einen Sinn darin, boost::ptr_vector nachzubauen ...
Ich auch nicht, aber wenn man den nicht zur Verfügung hat, geht es nicht anders.
krümelkacker schrieb:
cooky451 schrieb ironisch:
> Es ist so schlimm. Rohe besitzende Pointer sind das Böse. [...]
Jain. Je kleiner der Rahmen, desto besser und fehlerunanfälliger.
Ungefähr so klein wie der folgende?
cooky451 schrieb:
Und nicht, wie viele vielleicht vermuten mögen, weil man das vergessen könnte. Nein, da muss man zwar drauf achten, aber es gibt viel schlimmere Dinge:
void foo() { A* a = new A; bar(); // BAM, Exception, Fail. delete a; }Die sehr umständliche Fehlerbehandlung, die man mit RAII nicht benötigt:
A* a = new A; try { bar(); } catch (...) { delete a; throw; } delete a;Das würde ich nicht vergessen nennen. Eher verwechseln und zwar mit C, wo es keine Ausnahmen gibt. C++ wird überhaupt sehr oft mit C verwechselt. Im Nachhinein hätte man C++ ganz anders nennen müssen, weil es nichts mehr mit C zu tun hat. Ist so ähnlich wie bei Java und JavaScript.
Wenn C++ nicht aus C entstanden wäre, sondern von Anfang an als C++11 mit anderem Namen erschienen wäre, würde niemand auf die Idee kommen,deletejemals aufzurufen, weil die Assoziation mitfreeund Konsorten nicht so stark wäre.
-
Artchi schrieb:
Eisflamme schrieb:
Wenn man dran denkt am Ende zu löschen ist ein roher Pointer doch auch ok. Nie kapiert, was daran so schlimm sein soll...
Wenn er es vergisst, selber zu löschen... dann ist es schlimm.
Primäres Argument für mich ist nicht das Vergessen, sondern Exception-Sicherheit...
-
Hier ein Beispiel für die Smartpointeverweigerer, das sich nicht mehr mit try-catch wegreden lässt, selbst mit dem weitgehend unbekannten function-try-block:
#include <memory> #include <exception> class success {}; class fail { public: fail() {throw std::exception();} }; class naives_raii { success *s; fail *f; public: naives_raii(): s(new success), f(new fail) {} ~naives_raii() {delete f; delete s;} naives_raii(const naives_raii&) = delete; naives_raii operator=(const naives_raii&) = delete; }; template<typename T> class smartpointer { T* data; public: smartpointer(T* t): data(t) {} ~smartpointer() {delete data;} smartpointer(const smartpointer&) = delete; smartpointer operator=(const smartpointer&) = delete; }; class richtiges_raii { smartpointer<success> s; smartpointer<fail> f; public: richtiges_raii(): s(new success), f(new fail) {} }; int main() { try { richtiges_raii r; // Alles ok } catch(std::exception) {} try { naives_raii n; // Oh nein, Speicherleck! } catch(std::exception) {} }
-
Und new selbst darf ja auch noch werfen, nicht vergessen. Sehr schöner Fail ist z.B.
my_type t(new A, new B);Wenn das letztallokierte wirft, gibt's nen Speicherleck.
Bald können wir eine FailWithoutSmartpointersPedia aufmachen.

-
Da waren die C++ Programmierer ja echt arm dran vor 2011. Na ein Glueck gab es Java.
Wie oft passiert es, dass man mit
new'ne Exception bekommt und weitermachen moechte? Bei mir hatnewnoch nie eine Exception geworfen. Aber ich bin bestimmt die Ausnahme.
-
knivil schrieb:
Da waren die C++ Programmierer ja echt arm dran vor 2011.
In der Tat.
knivil schrieb:
Na ein Glueck gab es Java.
Das hat ganz andere Probleme.

knivil schrieb:
Wie oft passiert es, dass man mit
new'ne Exception bekommt und weitermachen moechte?Nicht so oft. Aber wie oft kommt es vor, dass überhaupt eine Exception geworfen wird, und man nicht an einem komplett anderen Punkt weiter machen möchte? Auch nicht so oft. Insofern stelle ich mal die Behauptung auf, dass sehr viele C++ Anwendungen so 100byte Speicher / Stunde verlieren, aber das fällt auf nem Desktopsystem halt nicht auf. Trotzdem bleibt es unsauber, und wenn dann mal irgendein Mutex nicht freigegeben wird, wird's erst richtig lustig. Daher kann man doch ruhig mal auf die vielen Fallstricke hinweisen. Insbesondere wenn sie so leicht vermeidbar sind.

-
knivil schrieb:
Da waren die C++ Programmierer ja echt arm dran vor 2011. Na ein Glueck gab es Java.
Das =delete habe ich nur aus Schreibfaulheit benutzt (und um hier im Forum mehr C++11 einzubringen. C++11 ist inzwischen alt genug, dass man nicht mehr auf C++98 pochen braucht). Das Problem und die Lösung gab es auch schon in C++98.
-
SeppJ schrieb:
Hier ein Beispiel für die Smartpointeverweigerer, das sich nicht mehr mit try-catch wegreden lässt, selbst mit dem weitgehend unbekannten function-try-block:
Geht alles
class naives_raii { success *s; fail *f; public: naives_raii() try : s(s=0,new success), f(new fail) {} catch (...) { delete s; } ...wird allerdings schnell kompliziert.
-
Ach der Kommaoperator! Da habe ich so lange getüftelt, wie man es wohl mit try...catch machen könnte (ich will ja nix falsches erzählen) aber dann denke ich nicht an diesen.

-
Am lustigsten sind immer noch operator = in abgeleiteten Klassen, die Thread & Exceptionsicher sein sollen. Sowas macht ohne RAII Spaß.
