Разбивают ли необязательные элементы RAII, и если да, то какой подход лучше? - PullRequest
2 голосов
/ 23 ноября 2010

У меня есть двумерная матрица клеток. Обычно с этими ячейками работают только невидимые алгоритмы. Но иногда я хочу визуализировать каждую ячейку, поэтому я добавил указатель на графический объект

class Cell
{
   ...
   QAbstractGraphicsItem* representation_;
   ...
}

Конструктор ячейки устанавливает представление_ равным 0. Иногда другой класс визуализации выполняет итерации в матрице и добавляет элементы в ячейки, которые визуализируют содержимое каждой ячейки с помощью цветов.

Я думаю, что это нарушает парадигму RAII. Есть ли у вас лучший подход?

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

Ответы [ 5 ]

5 голосов
/ 23 ноября 2010

RAII назван неправильно, как (я думаю) Скотт Мейерс отмечает.

Это не должно называться «Приобретение ресурсов - это инициализация», оно должно называться «Разрушение - это освобождение ресурсов».Но мы находимся там, где мы есть.

Если ячейка "владеет" объектом, на который указывает representation_, и удаляет его в своем деструкторе, то это все еще форма RAII, так же, как вы можетеинициализируйте shared_ptr с нулевым указателем, а затем установите его в другое значение.Я предполагаю, что вы используете его правильно (убедитесь, что объект был сохранен в какой-либо ячейке или другой сразу же после его создания, без шансов сбоя между завершением конструктора и сохранением указателя где-нибудь, где он будет в конечном итоге освобожден).Если это так, вы используете важную часть RAII, даже если это не конструктор, выполняющий работу.

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

Если Cell не «владеет» объектом, на который указываетrepresentation_, тогда это также не нарушает RAII, оно просто не реализует его.Что-то еще придется нести ответственность за владение объектом.Может быть, эта другая вещь использует RAII, может быть, это нарушает его.Чтобы гарантировать, что объект живет до тех пор, пока ячейка нуждается в нем, он должен был бы каким-то образом участвовать в жизненном цикле ячейки (например, если он владеет ячейкой, с вами может быть все в порядке).Так что, если это не так, есть большая вероятность, что он как-то нарушает RAII.

2 голосов
/ 23 ноября 2010

Я не думаю, что вы нарушаете RAII (Resource Acquisition Is Initialization), пока ваш деструктор Cell фактически удаляет объект QAbstractGraphicsItem (его деструктор является виртуальным, верно?), Если один есть. Однако вы, похоже, обеспокоены потенциальной связью между вашими графическими элементами и ячейками в этой архитектуре.

Да, привлекательно полностью отделить хранилище объектов от его презентации. Идеальный инструмент для этого (как указал Бен Фойгт) - это то, что позволяет вам расширить определение класса извне класса с помощью дополнительного элемента данных. Но C ++ не поддерживает это. Ваше предложение сохранить другую матрицу для указателей визуализации - лучшее, что я могу придумать, но тогда вам придется поддерживать эту вторую структуру данных. Если вы не хотите этого делать, вам придется пожертвовать этим идеальным разделением ради практической простоты.

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

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

2 голосов
/ 23 ноября 2010
1 голос
/ 23 ноября 2010

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

Обычный подход для статических языков, таких как C ++, заключается в создании подкласса Cell. Ваши алгоритмы должны отлично работать на матрице CellSubclass, хотя это немного усложняет ситуацию, если вы последовательно сохраняете элементы по значению в массиве. Вы можете продолжать делать это и шаблонизировать свои алгоритмы или хранить указатели в массиве.

Если вам действительно нужны свойства расширения, вы можете использовать map<void*,IPropertyValue*> внутри Cell, где IPropertyValue просто предоставляет виртуальный деструктор, чтобы не пропускать значения свойств расширения при освобождении Cell , Вам нужно будет разыграть при получении значения. Используйте адрес некоторой приватной статической переменной в качестве ключа, чтобы гарантировать уникальность и единообразие.

РЕДАКТИРОВАТЬ: Если вы хотите / должны хранить только один указатель, то ваш способ будет работать хорошо. Но используйте умный указатель и используйте swap при его назначении. Таким образом, все будет RAII.

0 голосов
/ 23 ноября 2010

Это нарушает RAII - вы должны использовать самораспускающийся указатель.

...