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.
-
@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.
-
@5cript sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
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"Der entscheidende Punkt ist, dass durch das Memory Overcommitment Eigenschaften des OS in Low Memory Situationen getriggert werden, die die Garantien der C++ ISO Norm konterkarieren. Die Norm garantiert Dir, dass eine Speicheranforderung entweder mit nullptr oder bad_alloc beantwortet wird, wenn der Speicher ausgeht, und man daraufhin das Programm zumindest wohl definiert beenden kann oder das Problem in einer anderen definierten Art und Weise lösen kannst. Genau das tritt dann aber nicht ein, sondern irgend ein Programm (es muss noch nicht einmal das Programm sein, dass die Low Memory Situation verschuldet hat) wird aus dem Speicher gekickt. D.h. das Laufzeitverhalten eines C++ Programm ist unter diesen Bedingungen eben nicht mehr definiert. Es ist UB nicht im streng formalistischen Sinne der Norm, sondern im dem Sinne, dass es Dir die Garantien der Norm unter den Füßen wegreißt.
Muss man deshalb so ein Fass in einem Anfänger Thread aufmachen? Ein kurzer Hinweis zur Klarstellung hätte ausgereicht. Anscheinend sind hier Nebensächlichkeiten wichtiger als der Umstand, dass man Anfänger klarmachen sollte, dass sie keine besitzenden Zeiger in Container ablegen sollten. Meiner Meinung eine vollkommen falsche Gewichtung der Thematik.
@5cript sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Ein Leak UB machen und dann ein leak detector erlauben passt nicht zusammen.
In der ISO Norm passt so einiges nicht zusammen. Ich hatte es an anderer Stelle schon angeführt, man darf zwar Allokatoren mit
propagate_on_container_swap == std::false_type
definieren, aber wenn man so einen Allokatoren mit einem Container verwendet und ein Swap stattfindet ist das UB. Das steht auch so in der Norm. Für C++17 noch verklausuliert, ab C++20 wohl direkt.
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Muss man deshalb so ein Fass in einem Anfänger Thread aufmachen?
Selbstgespräch?
Du hast doch deinen anfänglich guten Hinweis aus dem Ruder laufen lassen.
-
@john-0 sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
Muss man deshalb so ein Fass in einem Anfänger Thread aufmachen? [...] Anscheinend sind hier Nebensächlichkeiten wichtiger als [...]
Das ist doch Tradition hier - Aber wenn eine Aussage seltsam oder falsch ist, dann führt das natürlich dazu dass das diskutiert wird. Ich würde nichts anderes erwarten.
(Vorausgesetzt das grundlegende Problem wurde ausreichend diskutiert und aufgelöst)
-
@Jockelx sagte in vector mit basisklassen in einen mit abgeleiteten klassen casten?:
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?).@Jockelx:
Ich habe std::shared_ptr aus einer Mischung von Unwissenheit und Explorationsdrang genommen.Heißt ich habe einen Verwendungszweck für das Problem des TE gesehen und dachte mir dass das ein gutes Testprojekt für den Einsatz von C++11 Mitteln (std::unique_ptr und Co) sein könnte, da ich diese selten nutze.
Also habe ich ein Testprojekt aufgesetzt, damit ein wenig rumgespielt und verschiedene Szenarien getestet. Beispielsweise habe ich die Liste kopiert, danach verändert, die Liste danach Out Of Scope gehen lassen und die ursprüngliche Liste angesehen. Habe daher so Punkte wie
std::unique_ptr
oderfor (const auto&
vergessen, aber auch neue Dinge durch eurer Hinweise und Nachgooglen gelernt.Danke euch allen.