Вопрос владения/управления жизненным циклом


У меня есть небольшой класс 2D чертеж коммунальные услуги, Draw2D , который является глобальной точкой для все, что связано с рисованием. В настоящее время, класс выглядит так:

struct Draw2D
{
    std::shared_ptr<D2Label> CreateLabel (...);
    std::shared_ptr<D2Plot> CreatePlot (...);

    void Draw (D2Element& e);

    std::vector<std::weak_ptr<D2Element>> elements_;
};

struct D2Element
{ ... };

struct D2Label : D2Element
{ ... };

До сих пор так хорошо. Ключевой момент здесь заключается в том, что Draw2D должен знать все его элементы, чтобы их можно было обновить и для рисования, каждый элемент должен перезвонить своему родительскому Draw2D экземпляр. Т. е. вы не можете перемещать элементы между экземплярами, так как все элементы имеют ресурсов, предоставленных родителем. Решение у меня сейчас-это создание , которое провериться на каждого обновления Draw2D экземпляр и если устарело, то объект удаляется (то есть пользователь удалил его пока.)

Проблема в том, что после того, как экземпляр Draw2D умер, конечно, все еще существующие экземпляры тоже мертвы. Хотя они и являются технически обоснованными объектов, вы не можете использовать их безопасно больше. Даже запросы могут потерпеть неудачу, если они касаются общих ресурсов и сохраняя общий ресурс жив через shared_ptr не поможет, потому что просто откладывает проблемы пока чертеж серверной умирает (в этом случае все ресурсы будут считаться недействительными.)

Есть ли способ, чтобы переписать этот код, чтобы сделать его более ясным для клиентов? Я пробовал нечто подобное, как я определенно хочу, чтобы клиенты могли высвободить ресурсы рано (т. е. до Draw2D умирает.)

struct D2Element
{
    ~D2Element ()
    {
        deleter_ (this);
    }

    std::function<void OnDelete (D2Element*)> deleter_;
}

struct Draw2D
{
    void Release (D2Element* element)
    {
        // Remove from list of registered elements
    }

    ~Draw2D ()
    {
        // delete all remaining children
    }

    D2Label* CreateLabel (...)
    {
        auto label = ...;
        label->deleter_ = std::bind (&Draw2D::Release, this, _1);
        return label;
    }
}

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



231
3
c++
задан 11 сентября 2011 в 06:09 Источник Поделиться
Комментарии
1 ответ

Почему бы не отделить 2D-элемент на две части.


  • Интерфейс, который может быть использован

  • Общий ресурс

    • Используемый интерфейс Draw2D

    • Используется D2Elements.


Затем D2Elements не должны зависеть от объекта, который может выйти за пределы области, они имеют частичное право собственности на общий ресурс (с любым общие данные, что они и Draw2D должен.

class Draw2D
{
// interface as before
// Weak pointers as before.

std::shared_ptr<SharedResource> data;
};

class D2Element
{
//... As before.

std::shared_ptr<SharedResource> sharedData;
};

Даже Draw2D жизни заканчивается, то общий ресурс (т. к. это совместно с какой-либо созданные детьми), не умрет и таким образом не будут уничтожены.

1
ответ дан 11 сентября 2011 в 07:09 Источник Поделиться