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.
-
@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.
-
Mal abgesehen davon, dass die Klassenhierachie sehr fragwürdig ist, hast du einen shared_ptr genommen und keinen unique_ptr wie geschrieben.
Warum?
Und statt new nimm doch make_unique (bzw. shared) und deine for-schleife kopiert die ganze Zeit, was sie wohl nicht soll (darum?).
-
Jason Turner empfiehlt in seinen Talks immer,
shared_ptr
als Kopie zu übergeben, vermutlich um die Lifetime zu garantieren. Hab auf die Schnelle nur das hier gefunden, aber das schlägt wohl in die gleiche Kerbe
-
@DocShoe sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
aber das schlägt wohl in die gleiche Kerbe
Wie was? Auf welchen Post beziehst du dich gerade?
-
@Jockelx #
Auf den letzten Satz in deinem Post.@Jockelx sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
...
deine for-schleife kopiert die ganze Zeit, was sie wohl nicht soll (darum?).
-
Herb Sutter sagt in seinem GotW#91 wieder was anderes. Hmmm. Vielleicht verstehe ich auch nicht, was mit einem "aliased shared_ptr" gemeint ist.
Narf, am besten meine beiden letzten Posts ignorieren...
-
Ok, verstehe ich weiterhin nicht, was das Kopieren in der for-Schleife mit den Übergabe-Konventionen einer Funktion zu tun hat, aber worauf ich hinaus wollte ist eh, das @Quiche-Lorraine wahrscheinlich den unique_ptr ausgetauscht hat, weil der Kompiler da das Kopieren nicht machen wollte.
-
@Jockelx sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Ok, verstehe ich weiterhin nicht, was das Kopieren in der for-Schleife mit den Übergabe-Konventionen einer Funktion zu tun hat, aber worauf ich hinaus wollte ist eh, das @Quiche-Lorraine wahrscheinlich den unique_ptr ausgetauscht hat, weil der Kompiler da das Kopieren nicht machen wollte.
Ich steh grad´n bisschen neben mir, in den letzten 30min hab ich nix Vernünftiges geschrieben. Wie gesagt, am besten ignorieren.
-
@Quiche-Lorraine sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Ist das so ok?
Nein.
virtual ~RacingTeam() = default;
fehlt.
Und einenstd::vector
"List" zu nennen, ist auch fragwürdig.
-
@SeppJ sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Das ist kein undefined behavior.
Die ISO Norm sieht ein solches Verhalten gar nicht vor, da bewegt man sich komplett außerhalb der Norm.
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
@SeppJ sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Das ist kein undefined behavior.
Die ISO Norm sieht ein solches Verhalten gar nicht vor, da bewegt man sich komplett außerhalb der Norm.
Ist es dann auch undefined behaviour wenn ich winapi Funktionen falsch verwende? Davon steht auch nichts in der Norm.
EDIT:
Im Standard unter "4.1.1 Abstract machine" wird erklärt wie der Standard das beobachtbare Verhalten eines Programmes "garantiert", und dass so lange sich die Implementierung equivalent zu dem beobachtbaren Verhält, das diese Implementierung erlaubt ist / Standardkonform ist. (as-if rule)
Undefined Behaviour bedeutet, dass die Garantie des Programmverhaltens vollständig entfällt. (bla bla festplatte formatieren bla)Was Undefined Behaviour ist, ist im Standard nicht "undefined" sondern kommt sehr sehr oft vor "XYZ is undefined behaviour if".
Also "nicht definiert" != "C++ UB"
-
Übrigens hat der C++ Standard eine Grundbasis für einen Garbage Collector.
https://en.cppreference.com/w/cpp/memory/gc/pointer_safetyEin Leak UB machen und dann ein leak detector erlauben passt nicht zusammen.