std::vector mit unterschiedliche grossen Datentypen
-
@manni66 Ok. Also im Moment frage ich mich, für was es dann upcasting und downcasting gibt. Also ich bin am überlegen, einen std::vector mit smart_pointern zu verwenden, oder können dann auch Daten verloren gehen?
Oder gibt es geeignetere Container als vector für Klassen mit gemeinsamer Basisklasse?
Edit: Also in meinem konkreten Fall ist es glaube ich gar nicht so schlimm, da alle Daten in der Basisklasse gespeichert sind oder sogar mit OpenGL. Also ich habe shapes, z.B. QuadShape, Circle usw. Aber dass einfach Daten verloren gehen können, wenn man nicht aufpasst...
-
@titan99_ sagte in std::vector mit unterschiedliche grossen Datentypen:
@manni66 Danke für die rasche Antwort. Die Daten gehen also verloren. Das war mir neu.
Was heisst "geht verloren"? Wird ja gar nicht erst gespeichert, ist ja gar kein Code dazu da. std::vector<Foo> wird auch komplett ohne die Kenntnisvon Bar kompiliert. Der Fehler ist das dann so komisch rumzucasten, weswegen man das ja auch nicht machen sollte.
-
@titan99_ sagte in std::vector mit unterschiedliche grossen Datentypen:
Oder gibt es geeignetere Container als vector für Klassen mit gemeinsamer Basisklasse?
Das hat nichts mit dem Container zu tun.
Foo f = Bar{1,2,3,4,5,6};
macht das gleiche. f ist kein Bar!
-
Habe es noch mit
std::shared_ptr
versucht:int main(int argc, char** argv) { std::shared_ptr<Bar> bar0ptr = std::make_shared<Bar>(Bar(0, 1, 2, 3, 4, 5)); std::shared_ptr<Bar> bar1ptr = std::make_shared<Bar>(Bar(6, 7, 8, 9, 10, 11)); std::cout << "bar0 "; bar0ptr->print(); std::cout << "bar1 "; bar1ptr->print(); std::vector<std::shared_ptr<Foo>> store; store.push_back(bar0ptr); store.push_back(bar1ptr); auto downcast0 = std::static_pointer_cast<Bar>(store[0]); auto downcast1 = std::static_pointer_cast<Bar>(store[1]); std::cout << "downcast0 "; downcast0->print(); std::cout << "downcast1 "; downcast1->print(); }
Also so blieben alle Daten erhalten. Frage mich aber ob die Daten nur zufällig nicht verloren gehen. Richtig erklären kann ich es mir nicht ganz.
-
@titan99_ Verstehst du den Unterschied zwischen einem Objekt und einem Zeiger auf das Objekt?
-
@hustbaer Ja einigermassen. Also Objekte/Variablen haben eine Adresse und die Daten. Bei zusammenhängendem Speicher sind die Adressen zusammenhängend. Es wird glaube ich jeweils ein Byte adressiert, aber genau weiss ich es nicht.
Edit: Also wenn ich die Zeiger oder die Adressen im vector speichere, sind nur die Variablen wo die Adressen gespeichert sind im Speicher zusammenhängend.
-
@titan99_ sagte in std::vector mit unterschiedliche grossen Datentypen:
Edit: Also wenn ich die Zeiger oder die Adressen im vector speichere, sind nur die Variablen wo die Adressen gespeichert sind im Speicher zusammenhängend.
Bingo.
-
Beachte auch:
struct Foo { virtual void p() { cout << "Foo.\n"; } }; struct Bar : public Foo { void p() override { cout << "Bar.\n"; } }; Bar b; Foo f = b; f.p(); // Foo. //Aber: Bar *pb = new Bar; Foo *pf = pb; pf->p(); //Bar.
(Natürlich sonst auch an virtual ~Foo denken und Smartptr verwenden)
-
weiss nicht ob das sinnvoll ist, aber wenn man will dass alle objekte gleich groß sind, dann könnte man sie in eine union stecken. dabei gibt das größte objekt die größe vor.
-
@Bushmaster sagte in std::vector mit unterschiedliche grossen Datentypen:
weiss nicht ob das sinnvoll ist,
Nein. std::variant.
-
@titan99_ sagte in std::vector mit unterschiedliche grossen Datentypen:
Also im Moment frage ich mich, für was es dann upcasting und downcasting gibt. Also ich bin am überlegen, einen std::vector mit smart_pointern zu verwenden, oder können dann auch Daten verloren gehen?
Mit Smart Pointern kannst du das Problem umgehen.
-
@manni66 sagte in std::vector mit unterschiedliche grossen Datentypen:
@Bushmaster sagte in std::vector mit unterschiedliche grossen Datentypen:
weiss nicht ob das sinnvoll ist,
Nein. std::variant.
die idee hatte schon jemand; https://en.cppreference.com/w/cpp/utility/variant
The class template std::variant represents a type-safe union.
wurde aber erst 2017 umgesetzt.
-
@eigenartig sagte in std::vector mit unterschiedliche grossen Datentypen:
Mit Smart Pointern kannst du das Problem umgehen.
Quatsch. Das hat nix mit smarten Pointern zu tun sondern mit Laufzeitpolymorphie. Und das geht eben definitionsgemäß nur wenn man Referenzen (Pointer oder Referenzen) auf die verschiedenen Objekte hat. Man darf diese Pointer dann unter gewissen umstänten casten.
-
@manni66 sagte in std::vector mit unterschiedliche grossen Datentypen:
@Bushmaster sagte in std::vector mit unterschiedliche grossen Datentypen:
weiss nicht ob das sinnvoll ist,
Nein. std::variant.
variant ist cool. visual studio kennt es, nachdem c++17 in den compiler settings aktiviert wurde.
int main() { variant<int, double, char, long, string, char*> v; cout << sizeof(v) << endl; // 40 bytes wtf? v = 1234; auto val = get_if<int>(&v); cout << typeid(*val).name() << ": " << *val << endl;; v = 1234.5678; auto val2 = get_if<double>(&v); cout << typeid(*val2).name() << ": " << *val2 << endl;; }
bisschen viel overhead, aber das liegt wohl daran weil ich für debug compiliert habe.
-
Eher wegen dem string und SSO.
-
@Mechanics sagte in std::vector mit unterschiedliche grossen Datentypen:
Eher wegen dem string und SSO.
aber ich tue keinen string rein. die typenliste gibt doch nur an, was hinein darf.
-
@Bushmaster Und string mit SSO ist das größte was hinein kann und damit ist ein variant auch mindesten so groß. (und die Größe steht natürlich schon zur compiletime fest.)
-
@Swordfish sagte in std::vector mit unterschiedliche grossen Datentypen:
@Bushmaster Und string mit SSO ist das größte was hinein kann und damit ist ein variant auch mindesten so groß. (und die Größe steht natürlich schon zur compiletime fest.)
du kannst recht haben. im realease-modus sind es 32 bytes, also nur 8 bytes weniger.
-
Dieser Beitrag wurde gelöscht!
-
@wob sagte in std::vector mit unterschiedliche grossen Datentypen:
Natürlich sonst auch an virtual ~Foo denken
virtual dtor in der Basisklasse spielt aber nur eine Rolle, wenn abgeleitete Klassen einen Desktruktor implementiert haben, damit auch der Destruktor in der abgeleiteten Klasse aufgerufen wird? siehe stackoverflow.
Oder sollten Klassen, die einen dtor implementiert haben und von denen abgeleitet wird, immer virtual dtor haben?