2016-08-09 97 views
2

In meiner Methode ein Player-Objekt wird erstellt, wie:C++ erstellen Shared_ptr zu stapeln Objekt

Player player(fullName,age); 

Mein Lehrer gab uns ein Stück Code mit einem Konstruktor, der einen shared_ptr zu einem Spieler Aufgabe übernimmt.

//constructor of the class 
SomeClass(const std::shared_ptr<Socket> client, std::shared_ptr<Player> player) 

Nehmen wir an, wir wollen den Konstruktor von SomeClass aufrufen und das Player-Objekt übergeben, das wir auf Stapel erstellt haben.

Ist es jemals sicher/möglich/gut, ein shared_ptr aus einem Stapelobjekt zu erstellen?

Um die Frage verständlicher zu machen, sagen wir, wir haben zwei große Codeprojekte und wollen sie zusammenführen, damit eine Methode aus einem Projekt von einer anderen aufgerufen wird, sollten wir alle Dateien neu schreiben, um shared_ptr oder stack objects exclusivly zu verwenden (für die Methoden, die verbunden werden müssen) oder sollten wir nur ein shared_ptr für das Stack-Objekt erstellen.

Warum im nicht sicher über das Ergebnis:

Was passiert, wenn der Umfang, wo die stackobject Ende geschaffen wird, aber die Shared_ptr noch verwendet wird und umgekehrt.

Das Stackobject wird gelöscht, wenn es außerhalb des Gültigkeitsbereichs liegt oder bleibt es am Leben, weil es immer noch einen Verweis auf das Objekt (in einer anderen Klasse) gibt?

Die shared_ptr verlässt den Gültigkeitsbereich und versucht, das Objekt zu löschen, kann es, obwohl das Stackobject darauf Bezug nimmt?

Anmerkung: Ich weiß, dass ich nur die folgenden und passieren nutzen könnte Spieler

shared_ptr<Player> player{ new Player {fullName,age} }; 
+0

Mögliches Duplikat von [Set shared \ _ptr, um auf vorhandenes Objekt zu verweisen] (http://stackoverflow.com/questions/24049155/set-shared-ptr-to-point-existing-object) – Zereges

+0

Seitliche Notiz, wenn Sie in sind C++ 11 oder neuer, es ist eine gute Angewohnheit, 'make_shared' zu verwenden, wenn du kannst. in diesem Fall: 'auto player = std :: make_shared (fullName, Alter);' Es ist in den meisten Fällen effizienter und sicherer. –

Antwort

9

Ist es jemals sicher/möglich/gut, ein smart_ptr aus einem Stapelobjekt zu erstellen?

Sicher? Nur wenn Sie garantieren können, dass der Stapel, der dieses Objekt erstellt hat, nur nach allen shared_ptr beendet wird, die es pseudo-besitzen.

Möglich? Sicher: die nichts tut shared_ptr ‚s Konstruktor ein deleter Objekt übergeben:

auto sptr = shared_ptr<Player>(&player, [](Player *) {}); 

Wenn der letzte shared_ptr zerstört wird, wird die deleter genannt und nichts gelöscht werden.

Gut? Nicht wirklich. Wie oben erwähnt, ist Sicherheit in diesem Code nicht allgemein garantiert. Abhängig von Ihrer Codestruktur kann dies legitim sein. Aber es erfordert große Sorgfalt.

Diese SomeClass erwartet, Besitz einer Ressource zu beanspruchen; deshalb dauert es eine shared_ptr. Sie lügen es an, indem Sie ihm eine shared_ptr übergeben, die das Objekt, auf das es verweist, nicht wirklich besitzt. Das bedeutet, es liegt an Ihnen und an Ihrer Code-Struktur, das Versprechen, das Sie an SomeClass abgegeben haben, nicht zu verletzen, dass es die Kontrolle über die Lebensdauer dieses Objekts geteilt hätte.

2

Es ist nicht sicher einen gemeinsamen Zeiger auf ein Stapel-Objekt zu erstellen, weil das Stack-Objekt für Zerstörung zurückzuführen ist, sobald Seine enthaltene Funktion kehrt zurück. Lokale Objekte werden implizit und automatisch zugewiesen und freigegeben, und der Versuch, einzugreifen, ruft sicher viele Arten von undefiniertem Verhalten hervor.

1

Der Zweck eines gemeinsamen Zeigers ist es, die Lebensdauern von dynamisch erstellten Objekten zu verwalten. Solange es einen gemeinsamen Zeiger gibt, der auf ein Objekt zeigt, muss dieses Objekt noch existieren; Wenn der letzte gemeinsame Zeiger, der auf ein Objekt zeigt, zerstört wird, wird das Objekt zerstört.

Stapelobjekte haben eine grundlegend andere Lebensdauer: Sie existieren, bis der Code den Bereich verlässt, in dem sie erstellt wurden, und dann werden sie zerstört.

Die beiden Begriffe der Lebensdauer sind inkompatibel: Es gibt keine Möglichkeit, dass ein gemeinsam genutzter Zeiger sicherstellen kann, dass ein Stapelobjekt, das den Gültigkeitsbereich verlassen hat, immer noch existiert.

Also nicht die beiden mischen.

0

Sicher ist ein starkes Wort. jedoch können Sie den Code sicherer machen, indem ein StackObjectSharedPtr definieren, wodurch der shared_ptr instanziiert Typ eine „besondere“ StackObjectDeleter enthalten

using PlayerStackSP = std::shared_ptr <Player, StackObjectDeleter> ; 

class StackObjectDeleter { 
public: 
    void operator() (void*) const {} 
}; 

Player player(fullName,age); 
std::shared_ptr<PlayerStackSP, StackObjectDeleter> player(&player, StackObjectDeleter()); 

Die StackObjectDeleter die default_delete als deleter Objekt ersetzt. default_delete ruft einfach delete (oder lösche []) auf. Im Fall von StackObjectDeleter wird nichts passieren.

Dies ist ein weiterer Schritt von @ Nicol Bolas Antwort.