2016-11-05 9 views
-3

У меня есть сценарий, в котором мне нужно собрать все объекты типа в коллекции, но мне также нужен набор некоторых из его унаследованных типов. Пример:C++ общие указатели классов parent-children

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; 
} 

Однако, когда я хочу, чтобы уничтожить эти объекты, я на самом деле вызывать деструктор дважды для каждого ChargedPartice:

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

Как и может иметь набор дочерних объектов хранится в его статической контейнер и иметь интеллектуальные указатели, указывающие на них одним из своих родительских классов?

Я хочу, чтобы иметь возможность создавать объекты из родительского класса тоже, и иметь статический вектор-указатель родительского объекта, являющийся владельцем этих объектов.

Моя идея состоит в том, что я каким-то образом определяю пользовательский deleter для интеллектуальных указателей родительского класса, который вызывает вызов деструктора, когда объект не является элементом коллекции дочерних классов. Это возможно?

+0

Почему вы используете статический член для хранения этих частиц? – LmTinyToon

+0

При правильном использовании 'shared_ptr' двойные вызовы деструкторов не должны выполняться. Вы должны показать больше кода, возможно, mcve: http://stackoverflow.com/help/mcve – Waldheinz

+0

@ АлександрЛысенко Простой случай использования: я хочу рассчитать силу на заряженной частице из-за электростатических взаимодействий. Для этого мне нужно знать все остальные позиции заряженных частиц. –

ответ

1

Каждый ChargedParticle в то же время является Particle, поэтому вызова Particle::particleCollection.clear(); будет достаточно, чтобы удалить все выделенные объекты.

Чтобы использовать общий указатель в вашем случае вам необходимо иметь базовый класс (или someClass или Particle) наследоваться от std:: enable_shared_from_this, таким образом, общего указателя, созданного из него будет один и тем же счетчиком. В вашем примере это два разных экземпляра общего указателя, которые ничего не знают друг о друге.

И я не вижу причин, по которым виртуальный деструктор не будет достаточным для ваших нужд.

+0

Очистка частицыCollection не помогает мне с заряженнымParticleCollection. После односторонней очистки, если я зацикливаюсь на ней, она будет содержать оборванные указатели. Я использую виртуальные деструкторы, но я никогда не слышал об этом классе std :: enable_shared_from_this. Я проверю это, спасибо :) –

+0

@AdamHunyadi Вы можете использовать 'std :: weak_ptr' или удалить элементы из соответствующего массива в деструкторе. – teivaz

+0

Как использовать std :: weak_ptr в этом случае? –

0

Если вы используете его правильно, нет никаких проблем, имя класса не совпадает с именем класса, но я не думаю, что это имеет значение:

#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 расширяется из примера в Cpp Reference

вы не можете создать самопишущий класс с std::shared_ptr, потому что вы должны наследовать от std::enable_shared_from_this, но вы не можете назвать shared_from_this() в конструкторе, потому что:

Разрешено вызывать shared_from_this только на ранее разделяемом объекте, то есть на объекте, управляемом std :: shared_ptr. В противном случае поведение не определено (до C++ 17) std :: bad_weak_ptr выбрасывается (конструктором shared_ptr из построенного по умолчанию weak_this) (начиная с C++ 17).

+0

Это нехорошо, так как в моем вызове конструктора базового класса я не могу иметь указатель на производный класс. –

+0

@AdamHunyadi означает, что вы хотите самостоятельно зарегистрировать свой класс в этом списке? – Danh

+0

@AdamHunyadi И проблема в том, что когда конструктор не закончил, объект не существовал, если конструктор бросает, объект не существует, что говорит, что ваш вектор имеет объект, не существующий – Danh

 Смежные вопросы

  • Нет связанных вопросов^_^