Управление памятью в составном шаблоне

В последние недели я снова и снова сталкиваюсь с одной и той же проблемой. В своей основе я строю (направленную ациклическую) иерархию объектов, таких как:

  • a -> c
  • b -> c
  • b -> d

Экземпляр может иметь более одного родителя и более одного потомка. c может быть ценностью для читателей и писателей. b может быть составным значением. Иерархия легко создается фабрикой — например, a.setChild(new C()), Позже клиент заботится только о руте, по которому он звонит getValue() или же setValue(),

Мой вопрос: кто очищает иерархию? Кто отвечает за звонок delete на b или же c?

  1. Опция — фабрика создала узлы, фабрика должна удалить узлы:
    Мне не нравится этот вариант, потому что я понимаю фабрику в качестве замены для new, Странно держать фабрику до тех пор, пока созданные ею экземпляры не будут уничтожены.

  2. Вариант — «Умные» указатели:
    Гораздо менее хорошо, потому что это загрязняет интерфейс и вносит много сложностей для простых вещей, таких как указатели.

  3. Опция — графоподобный класс, который управляет памятью:
    Класс собирает все узлы a, b, c, d, … и предоставляет доступ к корню. Сами узлы ссылаются друг на друга, но не удаляют ни детей, ни родителей. Если «график» или составной менеджер уничтожается, он уничтожает все узлы.

Я предпочитаю последний вариант. Это, однако, усложняет построение иерархии. Либо вы строите иерархию снаружи и рассказываете графу о каждом отдельном узле, либо вы строите иерархию внутри графа, который пахнет как вариант 1. Граф может удалить только то, что ему известно. Поэтому утечки памяти как-то в дизайне, если вам нужно передать узлы на график.

Есть шаблон для этой проблемы? Какую стратегию вы предпочитаете?

Изменить 1 — 1 сентября 2014 г .: Извините, за неопределенность в отношении умных указателей. Я попытался избежать еще одного «вопроса об использовании умных указателей» и вместо этого сосредоточил внимание на альтернативных решениях. Тем не менее, я готов использовать умные указатели, если они действительно являются лучшим вариантом (или при необходимости).

На мой взгляд, подпись setChild(C* child) должно быть предпочтительнее, чем setChild(std::shared_ptr<C> child) по той же причине, что и для каждого цикла, следует отдавать предпочтение перед итераторами. Тем не менее, я должен признать, что, как std:string разделяемый указатель более конкретен в отношении его семантики.

С точки зрения сложности, каждая операция внутри узла теперь должна иметь дело с общими указателями. std::vector<C*> становится std::vector< std::shared_ptr<C> >Кроме того, каждый указатель содержит счетчик ссылок, чего можно было бы избежать, если бы были другие варианты.

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

Изменить 2 — 1 сентября 2014 г .:
Спасибо за весь вклад. Моя конкретная проблема: я получаю байтовый массив с, скажем, данными датчика. В какой-то момент мне говорят, какое значение записано где в этом массиве. С одной стороны, я хочу получить отображение от позиции в массиве до примитивного значения (int32, double, …). С другой стороны, я хочу объединить примитивные значения в сложные типы (структуры, векторы, …). К сожалению, не все отображения являются двунаправленными. Например. Я могу прочитать сравнение между значениями, но я не могу записать значения в соответствии с результатом сравнения. Поэтому я разделил читателей и писателей и позволил им, при необходимости, получить доступ к одному и тому же значению.

3

Решение

Вариант — «Умные» указатели: гораздо менее хороший, потому что он загрязняет
интерфейс, и вводит много сложности для простой вещи, такой
как указатели.

Умные указатели — это указатели с управлением памятью, которое именно то, что вам нужно.

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

Фактическое предоставление необработанных указателей в вашем интерфейсе косвенно приводит к гораздо большему загрязнению и сложности, поскольку вам необходимо задокументировать правила владения и срока действия, которые являются явными при использовании интеллектуальных указателей, что делает их еще более простыми в использовании, чем «простые указатели».

Кроме того, это, скорее всего, «футурный» способ действий: поскольку умные указатели c ++ 11/14 являются частью стандарта std::stringскажешь что std::string загрязняет интерфейс и вносит много сложности по сравнению с const char* ?

Если у вас есть проблемы с производительностью, тогда возникает вопрос: будет ли ваше альтернативное решение, созданное вручную, действительно более производительным (это нужно измерить), и стоит ли оно того, чтобы затратить время на разработку функции и поддержку кода?

5

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector