Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!
Werbeanzeige
Community-Fossil
Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer
Wenn das passieren kann, dann ist unique_ptr ohnehin die falsche Wahl. Für genau solche Fälle ist shared_ptr da. Denn offenbar brauchst Du das Objekt ja doch noch, wenn der Owner es zerstört hat. So ein Fall sollte aber niemals eintreten dürfen bei unique Ownership. Denn wenn jemand anderes das Ding noch referenzieren kann, obwohl der Owner es zerstört hat, liegt genau genommen eigentlich eine shared Ownership vor. Die rein non-owning referenzierenden Objekte sollte nie so lange leben können. Klingt für mich nach einem Design-Fehler.Die Frage ist nicht ob der Zeiger, der die Ressource besitzt ("owning"), expired ist, sondern der Zeiger, der die Ressource lediglich verwendet, aber nicht besitz (non-owning).
Ich möchte diese explizit eindeutige Ownership nicht teilen, d.h. shared_ptr ist für mich nicht relevant.
C-/C++-Quelltext |
|
1 2 3 4 5 6 7 |
template <class T> 116 class sole_ptr 117 : private std::unique_ptr<T> { 118 119 private: 120 std::vector<dynamic_ptr<T>*> observers; 121 ... |
Leider verrätst du nicht genug über das Problem, das lösen zu müssen du meinst, um hier viel sagen zu können. Ich bin mir allerdings sicher, dass sich ein besseres Design, in welchem dieses Problem von vorn herein nicht auftritt, finden ließe...
Also eine VC-Performance-Analyse sagt, dass die 77,7% der Gesamtlaufzeit des Programms dabei draufgeht weak_ptr::lock aufzurufen. Sonst brauchen alle Aufrufe fast gleich viel Zeit.
Wie erwartet ist das locken der weak_ptr das was am längsten dauert. Ich denke aber weak_ptr wird in deinem Design auf keinen Fall benötigt.
Außerdem müssen die Tests außerhalb von einer IDE wie Visual Studio durchgeführt werden. In Visual Studio sind Allokationen nämlich unverhältnismäßig langsam. Faktor 10 habe ich noch im Kopf, ich weiß aber nicht, ob das (noch?) stimmt.
Wenn das passieren kann, dann ist unique_ptr ohnehin die falsche Wahl. Für genau solche Fälle ist shared_ptr da. Denn offenbar brauchst Du das Objekt ja doch noch, wenn der Owner es zerstört hat. So ein Fall sollte aber niemals eintreten dürfen bei unique Ownership.
Denn wenn jemand anderes das Ding noch referenzieren kann, obwohl der Owner es zerstört hat, liegt genau genommen eigentlich eine shared Ownership vor.
Und diese Tests sind auch im Release Build gefahren? Performancemessung eines Debug Build ist leider ein witzloses Unterfangen...
Die Heapallokationen des std::vector machen die Performance deines Pointers geradezu lächerlich.
Wenn du deinen Performacetest um std::make_shared ergänzt oder auch nur den Fall ergänzt, dass mehrere Weak Pointer auf einen Besitzerpointer zeigen können, wird sich das Resultat ändern.
Quellcode |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
$clang++ -o bench bench.cpp -std=c++11 $ ./bench shared_ptr & weak_ptr: 4984ms shared_ptr only: 1229ms sole_ptr & dynamic_ptr: 2454ms unique_ptr & raw pointer: 1187ms $ clang++ -o bench bench.cpp -std=c++11 -O2 $ ./bench shared_ptr & weak_ptr: 651ms shared_ptr only: 154ms sole_ptr & dynamic_ptr: 180ms unique_ptr & raw pointer: 152ms |
Das Beispiel ist jetzt nicht das beste gewesen, aber es kann durchaus Anwendungsfälle geben, in denen das passieren darf. Eine Ressource kann ja zwischenzeitlich wegsterben, aber das hindert einen ja nicht daran, im Falle einer Exception eine neue anzufordern und damit weiter zu arbeiten.Zitat
Da würd ich nun doch erst nochmal schwer drüber nachdenken, wieso es denn zu dem Zustand kommen können sollte, dass Objekte, die OpenAL Buffer verwenden, den OpenAL Kontext überleben und wofür genau dieser Manager eigentlich gut ist...
Das ist tatsächlich ein nicht zu unterschätzendes Problem, zumal es während all' dieser Zeit den Destruktor-Thread blockiert. Allerdings ist das dann eher ein Fall von Design-Fehler beim Nutzer. Wenn man sich ein Objekt in dem Sinne nur "mal eben ausleiht", sollte es nicht vorkommen, dass ein usable_borrowed_ptr lange existiert. Immerhin wird man da vorm plötzlichen Wegsterben geschützt. Mit unique_ptr<T> und T* allein gibt es diese Blockade nicht. Stirbt die Ressource also während der Verwendung in einem anderen Thread weg, kommt es im Raw Pointer -Thread plötzlich zu einem Crash oder seltsamen Undefined Behavior, weil man mit gelöschtem Speicher arbeitet. Viel Spaß bei der Fehlersuche. Das funktioniert natürlich auch ohne Threads. Und unique_ptr kann wie gesagt den Fall nicht modellieren, in dem die Ressource zwischenzeitlich sterben darf.Zitat
Die" Zombieobjekte" im Heap können erst freigegeben werden, wenn auch alle Pointer die eigentlich nicht Besitzer sind, zerstört wurden.
C-/C++-Quelltext |
|
1 2 3 4 |
int main(int _argc, char** _argv) noexcept { asm volatile("lock cmpxchg8b %eax"); return 0; } // ::main |
Natürlich setzt das voraus, dass es im Sinne des Programms ist, dass mehrere den Besitzer besitzen.
Werbeanzeige