2016-11-05 4 views
-3

Ich habe ein Szenario, in dem ich alle Objekte eines Typs in einer Sammlung sammeln muss, aber ich brauche auch eine Sammlung von einigen seiner geerbten Typen. Beispiel:C++ freigegebenen Zeiger der Eltern-Kind-Klassen

class Particle: public someClass 
{ 
    ... 
    public: 
     static std::vector<std::shared_ptr<Particle>> particleCollection; 
} 

class ChargedParticle: public Particle 
{ 
    ... 
    public: 
    static std::vector<std::shared_ptr<ChargedParticle>> chargedParticleCollection; 
} 

Jedoch, wenn ich diese Objekte zerstören will, rufe ich tatsächlich den destructor zweimal für jeden ChargedPartice:

Particle::particleCollection.clear(); // Okay 
ChargedParticle::chargedParticleCollection.clear(); // Error: particles are already deleted 

Wie kann ich beide habe eine Sammlung des Kindes in seinem statischen gespeicherten Objekte Container und haben intelligente Zeiger, die auf sie von einer ihrer Elternklassen zeigen?

Ich möchte in der Lage sein, Objekte auch aus der Elternklasse zu erstellen, und den statischen Smart-Zeiger-Vektor der Eltern der Besitzer dieser Objekte sein.

Meine Idee ist, dass ich irgendwie ein benutzerdefiniertes Deleter für die Smartpointer der Elternklasse definiere, das nur den Destruktor aufruft, wenn das Objekt kein Element der Sammlung der Kindklasse ist. Ist das möglich?

+0

Warum verwenden Sie ein statisches Element, um diese Partikel zu speichern? – LmTinyToon

+0

Bei richtiger Verwendung von 'shared_ptr' sollten doppelte Destruktoraufrufe nicht auftreten. Sie sollten mehr Code zeigen, möglicherweise eine mcve: http://stackoverflow.com/help/mcve – Waldheinz

+0

@ АлександрЛысенко Einfacher Anwendungsfall: Ich möchte die Kraft auf einem geladenen Partikel aufgrund elektrostatischer Wechselwirkungen berechnen. Dazu muss ich alle anderen geladenen Teilchenpositionen kennen. –

Antwort

1

Jede ChargedParticle ist gleichzeitig eine Particle also Particle::particleCollection.clear(); Aufruf wäre genug, um alle zugeordneten Objekte zu entfernen.

Um freigegebene Zeiger in Ihrem Fall benötigen Sie Basisklasse haben (entweder someClass oder Particle) von std:: enable_shared_from_this somit freigegebenen Zeiger von ihm erstellt vererbt wird, um den gleichen Zähler teilen. In Ihrem Beispiel sind dies zwei verschiedene Instanzen eines gemeinsamen Zeigers, die nichts voneinander wissen.

Und ich sehe keinen Grund für virtuelle Destruktor nicht genug für Ihre Bedürfnisse.

+0

Das Löschen der particleCollection hilft mir nicht bei der chargedParticleCollection. Nach dem einseitigen Löschen, wenn ich darauf schleife, wird es hängende Zeiger enthalten. Ich benutze virtuelle Destruktoren, aber ich habe noch nie von dieser Klasse std :: enable_shared_from_this gehört. Ich werde es überprüfen, danke :) –

+0

@AdamHunyadi Sie können 'std :: weak_ptr' in Betracht ziehen oder Elemente aus dem entsprechenden Array in destructor entfernen. – teivaz

+0

Wie verwende ich in diesem Fall std :: weak_ptr? –

0

Wenn Sie es richtig verwenden, gibt es kein Problem, den Namen der Klasse ist nicht das gleiche mit Ihrem Klassennamen, aber ich glaube nicht, das wichtig ist:

#include <iostream> 
#include <type_traits> 
#include <tuple> 
#include <vector> 
#include <memory> 
struct Base 
{ 
    Base() { std::cout << " Base::Base()\n"; } 
    // Note: non-virtual destructor is OK here 
    ~Base() { std::cout << " Base::~Base()\n"; } 
}; 

struct Derived: public Base 
{ 
    Derived() { std::cout << " Derived::Derived()\n"; } 
    ~Derived() { std::cout << " Derived::~Derived()\n"; } 
}; 

int main() { 
    std::vector<std::shared_ptr<Base>> base_vector; 
    std::vector<std::shared_ptr<Derived>> derived_vector; 
    auto d = std::make_shared<Derived>(); 
    derived_vector.push_back(d); 
    base_vector.push_back(d); 
    // 2 function call below does not matter 
    base_vector.clear(); 
    derived_vector.clear(); 

} 

Demo von Beispiel in Cpp Reference erweitert wird

Sie können eine selbstregistrierende Klasse mit std::shared_ptr nicht erstellt werden, da Sie von std::enable_shared_from_this erben müssen, aber man kann da nicht shared_from_this() im Konstruktor rufen:

Es ist erlaubt, shared_from_this nur für ein zuvor gemeinsam genutztes Objekt aufzurufen, d. H. Für ein Objekt, das von std :: shared_ptr verwaltet wird. Ansonsten ist das Verhalten nicht definiert (bis C++ 17) std :: bad_weak_ptr wird geworfen (durch den shared_ptr-Konstruktor von einem default-konstruierten weak_this) (seit C++ 17).

+0

Das ist nicht gut, da ich in meinem Base-Klasse-Konstruktoraufruf keinen Zeiger auf eine abgeleitete Klasse haben kann. –

+0

@AdamHunyadi das bedeutet, dass Sie Ihre Klasse für diese Liste registrieren möchten? – Danh

+0

@AdamHunyadi Und das Problem ist, wenn der Konstruktor nicht beendet wurde, das Objekt nicht existiert hat, wenn der Konstruktor wirft, das Objekt existiert nicht, das besagt, dass Ihr Vektor ein nicht existierendes Objekt – Danh