Я хотел бы убедиться, что никто не может удалить какие-либо объекты из моей иерархии классов, кроме как с помощью предоставленного метода Destroy.
Обоснование состоит в том, что любой объект из этой иерархии должен получить специальный мьютекс записи, прежде чем он начнет разрушать себя, чтобы убедиться, что объекты не удаляются, пока их использует другой поток.
Я знаю, что мог бы предотвратить эту проблему с помощью подсчета ссылок, но это было бы гораздо большим изменением для системы, в том числе с точки зрения потенциального влияния на производительность и распределения памяти.
Есть ли способ как-то эффективно / разумно сделать все деструкторы защищенными, чтобы дочерние классы могли называть своих родителей деструкторами, в то время как посторонние должны использовать Destroy?
Одно из решений, которое является безопасным (т.е. оно не сгниет), которое я придумал, — сделать все деструкторы приватными и объявить каждый производный класс другом базового класса, но я бы предпочел что-то более элегантное, менее ручное и более простое. поддерживать (например, не требуется модифицировать базовые классы для их получения).
Есть ли что-нибудь подобное? Может быть, какой-нибудь умный трюк, который заставляет вещи «работать», как я хотел бы?
пс. Решение, которое я выбрал на данный момент, состоит в том, чтобы НЕ препятствовать тому, чтобы кто-либо вызывал delete во всех случаях (просто сделал это защищенным в базовом классе), но обнаружил эту ситуацию и прервал вызов в деструкторе базового класса.
Не пытайтесь заново изобретать механизмы жизни, предоставляемые языком.
Чтобы объект вашего класса был правильно инициализирован, он также должен быть в состоянии очистить себя.
В его конструктор передают либо мьютекс, либо средство получения мьютекса, которое он может использовать в своем деструкторе.
Спасибо за все ваши отзывы и обсуждение. Да — это доказало, что невозможно сделать то, что было бы моим естественным первым выбором 🙁 (чтобы «защита» деструктора действовала в производных классах так же, как это делает «виртуальность»).
Мое решение в данном конкретном случае (решение всех потенциальных проблем, связанных с возможностью совершать ошибки, путем введения новых производных классов, которые нарушают предыдущие соглашения, и сохранение решения в одном месте / поддерживаемом (без дублирования кода в производных классах и т. Д.)):
У меня были такие же потребности, но по другой причине. В рамках нашей компании почти все классы являются производными от общего BaseObject
учебный класс. Этот объект использует счетчик ссылок определить его время жизни. BaseObject
в частности, эти три метода: retain()
, release()
а также autorelease()
, вдохновленный Objective-C язык. Оператор delete
вызывается только внутри release()
когда счет удержания достигает 0. Никто не должен звонить delete
непосредственно, и это также нежелательно иметь BaseObject
экземпляры в стеке.
Поэтому все наши деструкторы должны быть protected
или же private
, Для обеспечения этого, поскольку я знаю, что это невозможно из языка, я написал сценарий Perl, который ищет все деструкторы в исходном каталоге и составляет отчет. Тогда сравнительно легко проверить, соблюдается ли это правило.
Я сделал сценарий общедоступным, доступным здесь: https://gist.github.com/prapin/308a7f333d6836780fd5
Это можно сделать с помощью тестирования. Для класса с защищенным деструктором вам нужно 2 контрольных примера:
Если оба теста работают, я думаю, вы можете быть уверены, что ваши классы защищены так, как вам нравится.
Я не знаю, можете ли вы реализовать это с помощью вашей системы сборки, но у меня есть пример использования bjam (из boost) в мерзавец. Код прост и работает для gcc и msvc. Если вы не знаете bjam, вы должны посмотреть inte Jamroot.jam. Я думаю, что без дальнейших комментариев понятно, как работает этот простой пример.