Как сделать деструкторы защищенными для всей иерархии классов в поддерживаемом виде?

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

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

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

Есть ли способ как-то эффективно / разумно сделать все деструкторы защищенными, чтобы дочерние классы могли называть своих родителей деструкторами, в то время как посторонние должны использовать Destroy?

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

Есть ли что-нибудь подобное? Может быть, какой-нибудь умный трюк, который заставляет вещи «работать», как я хотел бы?

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

5

Решение

Не пытайтесь заново изобретать механизмы жизни, предоставляемые языком.

Чтобы объект вашего класса был правильно инициализирован, он также должен быть в состоянии очистить себя.

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

1

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

Спасибо за все ваши отзывы и обсуждение. Да — это доказало, что невозможно сделать то, что было бы моим естественным первым выбором 🙁 (чтобы «защита» деструктора действовала в производных классах так же, как это делает «виртуальность»).

Мое решение в данном конкретном случае (решение всех потенциальных проблем, связанных с возможностью совершать ошибки, путем введения новых производных классов, которые нарушают предыдущие соглашения, и сохранение решения в одном месте / поддерживаемом (без дублирования кода в производных классах и т. Д.)):

  1. Сделайте все существующие деструкторы иерархии классов, которые я могу найти защищенными
  2. Предоставьте метод Destroy в базовом классе, который можно использовать для инициирования уничтожения этих объектов — при вызове метод подсвечивает флаг разрушенного объекта, который был должным образом уничтожен, и затем вызывает delete для него
  3. В деструкторе базового класса (когда мы до него доберёмся) установите флажок — если он не установлен, это означает, что кто-то ввел новый класс и напрямую вызвал удаление для него, или как-то иначе избегал проверок защиты компиляторами (злоупотребил дружбой и т. Д.) — В этом случае я отменяю приложение, чтобы убедиться, что проблема не может быть проигнорирована / пропущена
1

У меня были такие же потребности, но по другой причине. В рамках нашей компании почти все классы являются производными от общего BaseObject учебный класс. Этот объект использует счетчик ссылок определить его время жизни. BaseObject в частности, эти три метода: retain(), release() а также autorelease(), вдохновленный Objective-C язык. Оператор delete вызывается только внутри release() когда счет удержания достигает 0. Никто не должен звонить delete непосредственно, и это также нежелательно иметь BaseObject экземпляры в стеке.

Поэтому все наши деструкторы должны быть protected или же private, Для обеспечения этого, поскольку я знаю, что это невозможно из языка, я написал сценарий Perl, который ищет все деструкторы в исходном каталоге и составляет отчет. Тогда сравнительно легко проверить, соблюдается ли это правило.

Я сделал сценарий общедоступным, доступным здесь: https://gist.github.com/prapin/308a7f333d6836780fd5

1

Это можно сделать с помощью тестирования. Для класса с защищенным деструктором вам нужно 2 контрольных примера:

  1. одна функция (в одном файле), которая не компилируется, просто создавая такой объект
  2. одна функция (во втором файле), которая создает объект с производным классом, который компилируется.

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

Я не знаю, можете ли вы реализовать это с помощью вашей системы сборки, но у меня есть пример использования bjam (из boost) в мерзавец. Код прост и работает для gcc и msvc. Если вы не знаете bjam, вы должны посмотреть inte Jamroot.jam. Я думаю, что без дальнейших комментариев понятно, как работает этот простой пример.

0
По вопросам рекламы [email protected]