vector mit basisklassen in einen mit abgeleiteten klassen casten?
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Das ist nicht korrekt, da hier POD Zeiger auf Klassen abgelegt werden. Grundsätzlich sind alle Container der C++ Standard Library nicht dafür geeignet, dass man darin besitzende POD Zeiger auf Objekte ablegt, weil das zu UB führt. Wenn man besitzende Zeiger in Container ablegen will, muss man Smart Pointer nutzen d.h. shared_ptr oder unique_ptr.
soso
-
@DocShoe sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
soso
Was ist
D*
bzw.E*
für ein Typ?
-
@Th69 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Dann sind, deiner Meinung nach, alle bestehenden C++98-Programme mit
vector<X*>
UB?Wie wäre es mit korrektem Lesen? Das steht das Wort besitzenden und das sollte man nicht überlesen.
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
weil das zu UB führt
Warum?
vector<X*> v; v.push_back( new X );
ist dann UB,
X* aX; aX = new X;
aber nicht?
-
@manni66 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Warum?
vector<X*> v; v.push_back( new X );
ist dann UB,
X* aX; aX = new X;
aber nicht?
Beides zusammen leakt
ist UB, da kein delete ausgeführt wird.Wenn man korrekt rohe Zeiger nutzt,
int main () { int* p = new int; // do something with p delete p; }
hier gibt es kein Leak mehr
ist das kein UB, sofern "something" da nicht querschiesst.Aber bei
#include <vector> int main () { std::vector<int*> vec; vec.push_back(new int); // wird hier die Ownership an den Container übertragen } // <- und hier wird der Stack aufgeräumt und dann gibt es ein memory leak.
Bei der main function wird der Müll vom OS aufgeräumt, aber bei jeder anderen Funktion würdest Du hier bei jedem Aufruf ein
int
verlieren – nicht gut.
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Beides zusammen ist UB, da kein delete ausgeführt wird.
Citation needed.
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Beides zusammen ist UB, da kein delete ausgeführt wird.
Ist ein memory leak UB?
Auch "nach" einem vector kann aufgeräumt werden:
int main () { std::vector<int*> vec; vec.push_back(new int); // do something with vec for_each( begin(vec), end(vec), [](auto p) { delete p; } ); }
Aber es ist natürlich völlig richtig, dass besitzende Zeiger besser keine rohen Zeiger sind, ob in einem Container oder nicht.
-
@SeppJ sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Citation needed.
Sorry, das UB war an der Stelle falsch. Es leakt halt, und könnte in Folge ein UB ergeben. Da war ich in Gedanken schon wieder weiter.
-
@manni66 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Auch "nach" einem vector kann aufgeräumt werden:
Nur dann wenn der Container nicht bereits Objekte verloren hat, und der Sinn und Zweck eines Containers ist es, dass man sich genau darum nicht mehr kümmern muss.
-
Ein Memoryleak ist kein UB und führt auch nicht zu UB.
-
@Bashar sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Ein Memoryleak ist kein UB und führt auch nicht zu UB.
Erstaunlicherweise doch. Ich habe es auch nicht geglaubt und daher nachgeschlagen:
C++-Standard über object-lifetime:
A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitlycalling the destructor for an object of a class type with a non-trivial destructor. For an object of a class typewith a non-trivial destructor, the program is not required to call the destructor explicitly before the storagewhich the object occupies is reused or released; however, if there is no explicit call to the destructor or if adelete-expression(8.5.2.5) is not used to release the storage, the destructor shall not be implicitly called andany program that depends on the side effects produced by the destructor has undefined behavior
Sinn macht die Passage für mich nicht. Warum ist das undefined, wenn die Seiteneffekte nicht passieren, aber sich das Programm darauf verlässt? Sie passieren dann halt nicht, und das Programm ist falsch, aber das sollte doch meines Erachtens nach definiert sein. Da sehe ich keinen Unterschied zu einem Programmierfehler. Aber da steht, dass es undefiniert sei, und dann ist es eben so.
-
@Bashar sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Ein Memoryleak ist kein UB und führt auch nicht zu UB.
Dir ist schon bewusst, dass z.B. unter Linux in low memory Situationen Prozesse einfach mal so abgeschossen werden?
By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. In case it turns out that the system is out of memory, one or more processes will be killed by the OOM killer. For more information, see the description of /proc/sys/vm/overcommit_memory and /proc/sys/vm/oom_adj in proc(5), and the Linux kernel source file Documentation/vm/overcommit-accounting.
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
@Bashar sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Ein Memoryleak ist kein UB und führt auch nicht zu UB.
Dir ist schon bewusst, dass z.B. unter Linux in low memory Situationen Prozesse einfach mal so abgeschossen werden?
By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. In case it turns out that the system is out of memory, one or more processes will be killed by the OOM killer. For more information, see the description of /proc/sys/vm/overcommit_memory and /proc/sys/vm/oom_adj in proc(5), and the Linux kernel source file Documentation/vm/overcommit-accounting.
Das ist kein undefined behavior.
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
@Th69 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Dann sind, deiner Meinung nach, alle bestehenden C++98-Programme mit
vector<X*>
UB?Wie wäre es mit korrektem Lesen? Das steht das Wort besitzenden und das sollte man nicht überlesen.
Das hatte ich schon gelesen, aber wie soll man denn einen nicht-besitzenden Zeiger in den
vector<X*>
packen (das wäre, mit C++98 Mitteln, ja noch komplizierter)?Und zu
Nur dann wenn der Container nicht bereits Objekte verloren hat, ...
Wie soll der Container denn Objekte verlieren?
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
@Bashar sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Ein Memoryleak ist kein UB und führt auch nicht zu UB.
Dir ist schon bewusst, dass z.B. unter Linux in low memory Situationen Prozesse einfach mal so abgeschossen werden?
Ja, das ist mir bewusst, und dein Ton gefällt mir nicht.
-
@SeppJ sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Aber da steht, dass es undefiniert sei, und dann ist es eben so.
Das bezieht sich aber auf
the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released
Bei einem Leak wird der Speicher nicht freigegeben oder wiederverwendet.
-
@manni66 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
@SeppJ sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Aber da steht, dass es undefiniert sei, und dann ist es eben so.
Das bezieht sich aber auf
the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released
Bei einem Leak wird der Speicher nicht freigegeben oder wiederverwendet.
Ja? Was willst du mir sagen? Da steht ganz explizit, wenn sich das Programm darauf verlässt, dass der Destruktor geschieht, ihn aber niemals selber aufruft, dann ist das Verhalten undefiniert.
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
@Bashar sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Ein Memoryleak ist kein UB und führt auch nicht zu UB.
Dir ist schon bewusst, dass z.B. unter Linux in low memory Situationen Prozesse einfach mal so abgeschossen werden?
By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. In case it turns out that the system is out of memory, one or more processes will be killed by the OOM killer. For more information, see the description of /proc/sys/vm/overcommit_memory and /proc/sys/vm/oom_adj in proc(5), and the Linux kernel source file Documentation/vm/overcommit-accounting.
Das OS kann nicht entscheiden, ob der Prozess sehr viel Speicher braucht, weil es Speicher leakt, oder weil die Datenmenge tatsächlich so groß ist. Nach deiner Aussage würden dann auch Programme, die irre viel Speicher brauchen, ebenfalls UB hervorrufen. Das ist dann unabhängig von der Korrektheit des Programms.
Die ursprüngliche Aussage Grundsätzlich sind alle Container der C++ Standard Library nicht dafür geeignet, dass man darin besitzende POD Zeiger auf Objekte ablegt, weil das zu UB führt ist in jeder Hinsicht falsch.
-
@SeppJ sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Was willst du mir sagen? Da steht ganz explizit, wenn sich das Programm darauf verlässt, dass der Destruktor geschieht, ihn aber niemals selber aufruft, dann ist das Verhalten undefiniert.
Das verstehe ich anders. Es geht darum, was passiert, wenn das Programm die Lebenszeit eines Objekts bendet. Bei einem Leak wird die Lebenszeit aber nicht beendet.
-
@hustbaer
Eine Frage. Vor kurzem habe ich älteren Code auf den Stand von C++11 gebracht, in dem ich einen nackten Schnittstellen-Zeiger in einen std::unique_ptr<> gepackt habe.Bezogen auf das vermutliche Problem des Threaderstellers sähe meine Lösung so aus:
#include <vector> #include <cstdio> #include <memory> class RacingTeam { public: virtual void PrintName() = 0; }; class BMW : public RacingTeam { public: void PrintName() override { printf("BMW\n"); } }; class Porsche : public RacingTeam { public: void PrintName() override { printf("Porsche\n"); } }; class Audi : public RacingTeam { public: void PrintName() override { printf("Audi\n"); } }; class Frikadelli : public RacingTeam { public: void PrintName() override { printf("Frikadelli\n"); } }; int main() { std::vector<std::shared_ptr<RacingTeam>> List; List.emplace_back(new BMW()); List.emplace_back(new Audi()); List.emplace_back(new Porsche()); List.emplace_back(new Frikadelli()); for (auto e : List) e->PrintName(); return 0; }
Ist das so ok?
Ich bin bei der Umstellung auf C++11 des öfteren überrascht und manchmal noch ein wenig unsicher, da es bei mir öfters zu kleinerem und weniger fehleranfälligen Code führt. Und wie schon gesagt, entdeckte ich vor kurzen noch klassischen objektorientierten Schnittstellen Code.