this zu shared_ptr casten
-
Hallo,
ich schreibe grade ein Programm, was bisher alte c-pointer verwendet hat und will das mit shared_ptr etwas aufpolieren.
Dabei habe ich aber das Problem, dass ich jetzt Zeigerargumente in std::shared_ptr umwandeln will und in einigen Funktionen this als Parameter habe.Vorher:
void Object::function(std::array<param_class *> parameters);
Nachher:
void Object::function(std::array<std::shared_ptr<param_class>> parameters);
Ich rufe im Programm aus der param_clas die Funktion Object::function auf. Ich weiß, dass das nicht so toller standard ist, aber das lässt sich im Augenblick nicht anders lösen.
Im ersten fall habe ich dafür einfacho->function({this})
aufgerufen.
Im zweiten Fall müsste ich vorher this in einen shared_ptr casten.
Etwa so:o->function({std::shared_ptr<param_class>(this)})
Ich frage mich jetzt hierbei, ob nach dem Aufruf this gelöscht wird, oder ob das zu anderen Problemen kommt, da das Memory von this nicht gefreed werden kann.
Ist es problemlos möglich this in einen shared_pointer zu casten oder sollte ich lieber die Funktion überladen, und einmal mit shared_ptr und einmal mit regulären Pointern arbeiten?Vielen Dank!
-
habs nur überflogen, aber: std::shared_from_this.
{this} ist nicht nur falsch, es ist eine Absturzgarantie.EDIT: Falls dein Objekt nicht von Anfang an, und nicht zwingend in einem shared_ptr lebt, und das nicht irgendwie sehr wichtig ist, würde ich die Übergabe als shared_ptr an eine Funktion stark in Frage ziehen.
-
5cript schrieb:
habs nur überflogen, aber: std::shared_from_this.
{this} ist nicht nur falsch, es ist eine Absturzgarantie.EDIT: Falls dein Objekt nicht von Anfang an, und nicht zwingend in einem shared_ptr lebt, und das nicht irgendwie sehr wichtig ist, würde ich die Übergabe als shared_ptr an eine Funktion stark in Frage ziehen.
Naja, ich brauche auf jeden Fall Pointer, weil meine Klassen virtual functions haben, und ich die Objekte dann nicht direkt übergeben kann.
Die einzige Alternative ist dann wohl die Funktion überladen oder die alten Pointer benutzen, oder?
-
-
Die Sache beim
shared_ptr
ist die, dass einshared_ptr
einen Referenzzähler braucht. Ein normales Objekt hat sowas nicht, also legt einshared_ptr
für jedes referenzierte Objekt einen Referenzzähler an und teilt sich ihn mit anderenshared_ptr
.shared_ptr<T> s1( new T() ); shared_ptr<T> s2 = s1;
s1
legt im Konstruktor einen referenzzähler für das verwaltete Objekt an unds2
benutzt den gleichen Referenzzähler. Soweit alles gut.void f1( const shared_ptr<T>& ptr ) { ... } void f2( T* ptr ) { // ptr lebt im shard_ptr p, für den Aufruf von f1/ wird aber ein shared_ptr // benötigt. Wenn ptr für den Aufruf von f2 in einen neuen shared_ptr // verpackt wird führt das zu doppelter Speicherfreigabe => BOOM f1( shared_ptr<T>( ptr ) ); } int main() { shared_ptr<T> p( new T() ); f2( p.get() ); }
Hier werden zwei
shared_ptr
mit jeweils eigenem Referenzzähler erzeugt. Im Destruktor geben beide den Speicher wieder frei und erzeugen damit UB. Soweit nicht mehr alles gut.Eine Lösung dazu ist, von
enable_shared_from_this
zu erben, in diesem Fall hängt der Referenzzähler nicht amshared_ptr
, sondern am verwalteten Objekt.struct T : std::enable_shared_from_this<T> { ... };
Alle
shared_ptr
, die jetzt auf einT
verwalten, benutzen den gemeinsamen Referenzzähler vonT
. Wieder alles gut.Das ist eine Lösung, wenn es wtrklich nicht anders geht. Ansonsten bin ich vollkommen bei 5cript: Man muss keine shared_ptr herumreichen. Der Besitzer weiß, dass ein Objekt in einem shared_ptr lebt, für die weitere Benutzung sollten dann Referenzen (falls Funktionsargument erforderlich ist) oder rohe Zeiger benutzt werden (falls Funktionsargument optional ist).
-
DocShoe schrieb:
Eine Lösung dazu ist, von
enable_shared_from_this
zu erben, in diesem Fall hängt der Referenzzähler nicht amshared_ptr
, sondern am verwalteten Objekt.(...)
Alle
shared_ptr
, die jetzt auf einT
verwalten, benutzen den gemeinsamen Referenzzähler vonT
. Wieder alles gut.Soweit ich weiss stimmt das nicht, der Control-Block ist nach-wie-vor extra. Zumindest war das lange Zeit in der Boost-Implementierung so.
Der Trick beienable_shared_from_this
ist dass das Objekt nenweak_ptr
auf sich selbst hat, der beim Erzeugen des 1.shared_ptr
auf das Objekt befüllt wird.Und AFAIK ist es auch nicht erlaubt über den normalen
shared_ptr(T*)
Ctor mehrereshared_ptr
auf das selbe Objekt zu erzeugen, auch nicht wenn die Klasse vonenable_shared_from_this
abgeleitet ist. Sondern man muss sich die weiterenshared_ptr
überobj.shared_from_this()
besorgen.Falls ich mich irre, bitte korrigiert mich!
-
Du hast recht, Hustbär!
Ich habe mich mit dem Thema vor über 7 Jahren beschäftigt, da ist wohl nicht allzuviel hängen geblieben.
-
Mit
boost::intrusive_ptr
kann man meinen o.g. Vorschlag implementieren. Wenn´s denn sein muss.