2016-06-20 9 views
0

im Konstruktor initialisiert wird ich einige Codes habe wie folgt strukturiert:Shared_ptr kann nicht, wenn `this` beteiligt

#include <memory> 
#include <vector> 

using namespace std; 
struct demo { 
    vector<shared_ptr<demo>> foo{shared_ptr<demo>(this)}; 
    void append(){ 
     foo.push_back(make_shared<demo>()); 
    } 
}; 

demo dummy(/* accept some arguments */){ 
    demo a{}; 
    a.append(); 
    return a; 
} 

int main() 
{ 
    demo bar=dummy(); 
    return 0; 
} 

Die Dummy-Funktion nur einen Prozess tun auf der Grundlage seiner Argumentation auf einer neuen Demo-Instanz aufgebaut und es zurück. (ich bin mir ziemlich sicher, dass die oben genug ist, um das Problem zu belichten)

Es kompiliert und ohne Fehler, aber es wird nicht selbst beenden. (Ich verwende g ++ von MinGW auf Win7).

Dann versuche ich zu arbeiten. Ich habe einen Kopierkonstruktor (sowie einen expliziten Standardkonstruktor) hinzugefügt und dann new verwendet, um nur einen Zeiger auf demo in der Hauptfunktion zu behalten. So wird der Code etwas wie sein:

... 
struct demo { 
    vector<shared_ptr<demo>> foo {shared_ptr<demo>(this)}; 
    void append() { 
     foo.push_back(make_shared<demo>()); 
    } 
    demo(){ 
    }; 
    demo(const demo& instance): foo(instance.foo) { 
    } 
}; 
... 
int main() 
{ 
// demo bar=dummy(); 
    demo* bar=new demo(dummy()); 
    delete bar; 
    return 0; 
} 

Dann hat es einfach funktioniert. Aber ich frage mich immer noch nach dem Mechanismus hinter diesen Linien. Würden Sie einfach erklären, was der Unterschied zwischen der new konstruierten und normal deklarierten Variablen ist?

EDIT: So endlich ist es überhaupt zu push_backthis in einen Vektor als struct Mitglied in seinem Konstruktor? (Aus dem Grunde, ist es, weil der Rest meines Vektor speichert all shared_ptr mit Ausnahme des ersten, in anderen Worten, selbst wenn der Vektor pop_back ed ist leer zu sein, ist es noch this zurückkehren kann)

+0

'bar' wird nicht automatisch gelöscht:' demo * bar = neues demo (dummy()); 'es leckt. –

+4

Sie sollten 'shared_ptr (this)' vermeiden (da Sie keine Garantie haben, dass Sie 'this' vorher besitzen), könnte 'enable_shared_from_this' helfen. – Jarod42

+0

Sie können kein Objekt annehmen, das ausschließlich einem anderen gehört, und entscheiden, dass es geteilt werden soll. Teilen muss eine gegenseitige Vereinbarung sein oder Dinge können ernsthaft schief gehen. – molbdnilo

Antwort

3

Hier ist ein minimalistisches Beispiel dafür ist, dass reproduziert Ihr Problem:

struct demo { 
    shared_ptr<demo> foo{this}; 
}; 

int main() 
{ 
    demo bar; 
} 

Das Problem ist, dass Sie einen freigegebener Zeiger auf this speichern, in einem Mitglied. Wenn also eine demo Instanz zerstört wird, wird der gemeinsame Zeiger dekrementiert, und wenn der gemeinsame Zeiger auf Null dekrementiert wird, wird das Objekt wieder gelöscht, was zu undefiniertem Verhalten führt.

Auch wenn das nicht das Problem war, gibt es immer noch das Problem, dass bar ein automatisches Objekt ist. Und Sie haben möglicherweise keine Zeiger auf automatische Objekte freigegeben. Aber bar erstellt einen gemeinsamen Zeiger auf sich selbst.

demo* bar=new demo(dummy()); 
delete bar; 

Das ist besser, weil jetzt das Objekt (spitz durch bar) hat dynamische Speicher, so können Sie einen freigegebenen Zeiger auf sie haben. Sie müssen natürlich dummy beheben, um keine automatische demo Instanz zu erstellen.

Sie können auch nicht explizit delete eine Instanz von demo, weil es eine gemeinsame zeigt auf sich selbst zeigt. Die „richtige“ Art und Weise eine Instanz von demo würde zu entsorgen sein, den gemeinsamen Zeiger zu entfernen, die dann Pflege der Löschung nehmen würden:

demo* bar=new demo(dummy()); 
bar->foo.clear();  // this is for your vector version 
//bar->foo = nullptr; // this is for my minimized example above 
// object pointed by bar no longer exists 
// (unless the shared pointer was copied and exists elsewhere) 

Allerdings finde ich das Design ist sehr verwirrend, und würde es nicht empfehlen.Sie sollten überdenken warum Sie einen gemeinsamen Zeiger auf this speichern.

+0

Stimmen Sie vollständig mit der Erklärung * undefined Behaviour * überein. Aber wie ich es versuchte, reproduziert der Code mein Problem nicht (kompiliert und ausgeführt), und ich persönlich glaube, dass das Problem in der Funktion liegt. Und was meinst du mit "Bar" ist und automatische Variable? – YiFei

+0

@YiFei Ich meine, dass die Variable [automatische] (http://en.cppreference.com/w/cpp/language/storage_duration#Storage_duration) Speicherdauer hat. Mein minimiertes Beispiel hat möglicherweise nicht das gleiche Verhalten wie Ihres, weil das Verhalten nicht definiert ist. Trotzdem zeigt es den gleichen Fehler. – user2079303

+0

Hinweis, ich habe 'Variable' für bessere Allgemeingültigkeit in 'Objekt' geändert. – user2079303

0

Entweder schafft a auf dem stapeln oder lassen Sie eine shared_ptr ihre Lebensdauer verwalten, aber Sie können nicht beides tun. Objekte auf dem Stapel verschwinden, wenn der Stapel weggeht.

Verwandte Themen