Из того, что я вижу, есть две распространенные формы управления ресурсами: детерминированное уничтожение и явное. Примерами первых могут быть деструкторы и интеллектуальные указатели C ++ или подпрограмма DESTROY в Perl, а вторым примером может служить парадигма Ruby «блоки для управления ресурсами» или интерфейс IDispose .NET.
Более новые языки, кажется, выбирают последнее, возможно, в качестве побочного эффекта от использования систем сбора мусора разновидности без подсчета ссылок.
Мой вопрос заключается в следующем: учитывая, что деструкторы для интеллектуальных указателей или систем сбора мусора с подсчетом ссылок - почти одно и то же - допускают неявное и прозрачное уничтожение ресурсов, является ли это менее запутанной абстракцией, чем недетерминированные типы, которые полагаются на явные нотация?
Я приведу конкретный пример. Если у вас есть три подкласса C ++ одного суперкласса, у одного может быть реализация, которая не требует какого-либо конкретного уничтожения. Возможно, это делает свое волшебство по-другому. Тот факт, что для этого не нужно никакого специального уничтожения, не имеет значения - все подклассы все еще используются одинаково.
Другой пример использует блоки Ruby. Два подкласса должны освободить ресурсы, поэтому суперкласс выбирает интерфейс, который использует блок в конструкторе, даже если другие конкретные подклассы могут не нуждаться в этом, поскольку они не требуют специального уничтожения.
Является ли тот случай, что последний утечки детали реализации уничтожения ресурса, а первый нет?
РЕДАКТИРОВАТЬ: Сравнение, скажем, Ruby с Perl может быть более справедливым, так как один имеет детерминистическое разрушение, а другой нет, но они оба сборщик мусора.
источник
(*ptr).Message()
или аналогичноptr->Message()
. Существует бесконечный набор разрешенных выражений, что((*ptr))->Message
также эквивалентно. Но все они сводятся кexpressionIdentifyingAnObject.Message()
Ответы:
Ваш собственный пример отвечает на вопрос. Прозрачное разрушение явно менее протекает, чем явное разрушение. Может протекать, но менее протекает.
Явное уничтожение аналогично malloc / free в C со всеми подводными камнями. Может быть, с каким-то синтаксическим сахаром, чтобы он выглядел на основе контекста.
Некоторые из преимуществ прозрачного уничтожения по сравнению с явным: -
тот же шаблон
использования - вы не можете забыть освободить ресурс.
- Очистить детали не засоряют пейзаж в месте использования.
источник
Ошибка в абстракции на самом деле не в том, что сборка мусора недетерминирована, а в том, что объекты «заинтересованы» в вещах, на которые они ссылаются, и не интересуются вещами, на которые они не держатся. Ссылки. Чтобы понять почему, рассмотрим сценарий объекта, который поддерживает счетчик того, как часто рисуется конкретный элемент управления. При создании он подписывается на событие рисования элемента управления, а при удалении отписывается. Событие click просто увеличивает поле, а метод
getTotalClicks()
возвращает значение этого поля.Когда объект счетчика создан, он должен заставить ссылку на себя быть сохраненной в элементе управления, который он отслеживает. Элемент управления действительно не заботится об объекте счетчика и был бы так же рад, если бы объект счетчика и ссылка на него перестали существовать, но пока ссылка существует, он будет каждый раз вызывать обработчик событий этого объекта он рисует сам. Это действие абсолютно бесполезно для контроля, но будет полезно любому, кто когда-либо будет вызывать
getTotalClicks()
объект.Если, например, метод должен был создать новый объект «счетчик краски», выполнить какое-либо действие с элементом управления, наблюдать, сколько раз элемент управления был перекрашен, а затем отказаться от объекта счетчика краски, объект останется подписанным на событие, даже хотя никому не было бы дела, если бы объект и все ссылки на него просто исчезли. Однако объекты не могут быть собраны, пока не получен сам элемент управления. Если бы метод был вызван много тысяч раз за время существования элемента управления (вероятный сценарий), он мог бы вызвать переполнение памяти, но тот факт, что стоимость N вызовов, вероятно, будет O (N ^ 2) или O (N ^ 3), если обработка подписки не была очень эффективной и большинство операций фактически не включало рисование.
Этот конкретный сценарий может быть реализован путем предоставления элементу управления слабой ссылки на контр-объект, а не сильной. Модель слабой подписки полезна, но не работает в общем случае. Предположим, что вместо того, чтобы хотеть иметь объект, который отслеживает один тип события из одного элемента управления, нужно иметь объект регистрации событий, который контролирует несколько элементов управления, а механизм обработки событий системы был таков, что каждому элементу управления нужна ссылка в другой объект журнала событий. В этом случае объект, связывающий элемент управления с регистратором событий, должен оставаться активным только до тех пор, пока обаконтролируемый элемент управления и регистратор событий остаются полезными. Если ни элемент управления, ни регистратор событий не содержат строгой ссылки на связывающее событие, оно прекратит свое существование, даже если оно все еще «полезно». Если один из них содержит сильное событие, время жизни связывающего объекта может быть бесполезно продлено, даже если другой умирает.
Если нигде во вселенной нет ссылки на объект, объект можно смело считать бесполезным и исключить из существования. Однако тот факт, что ссылка существует на объект, не означает, что этот объект «полезен». Во многих случаях фактическая полезность объектов будет зависеть от наличия ссылок на другие объекты, которые - с точки зрения GC - совершенно не связаны с ними.
Если объекты детерминированы уведомлением, когда никто не заинтересован в них, они смогут использовать эту информацию, чтобы гарантировать, что каждый, кто извлечет выгоду из этих знаний, будет проинформирован. Однако в отсутствие такого уведомления не существует общего способа определить, какие объекты считаются «полезными», если известно только существующее множество ссылок, а не семантическое значение, связанное с этими ссылками. Таким образом, любая модель, которая предполагает, что наличие или отсутствие ссылок достаточно для автоматизированного управления ресурсами, будет обречена, даже если GC сможет мгновенно обнаруживать отказ от объекта.
источник
Никакой «деструктор или другой интерфейс, который говорит« этот класс должен быть уничтожен », не является контрактом этого интерфейса. Если вы создадите подтип, который не требует специального уничтожения, я бы склонен считать, что нарушение принципа подстановки Лискова ,
Что касается C ++ и других, то особой разницы нет. C ++ использует этот интерфейс для всех своих объектов. Абстракции не могут вытекать, когда они требуются языком.
источник
DerivedFooThatRequiresSpecialDestruction
может быть создано только кодом, который вызываетnew DerivedFooThatRequiresSpecialDestruction()
. С другой стороны, фабричный метод, возвращающийDerivedFooThatRequiresSpecialDestruction
код, который не ожидал чего-либо, требующего уничтожения, был бы нарушением LSP.Необходимость следить за циклами вручную не является ни скрытой, ни прозрачной. Единственным исключением является система подсчета ссылок с языком, который запрещает циклы по дизайну. Эрланг может быть примером такой системы.
Так что оба подхода протекают. Основное отличие состоит в том, что деструкторы распространяются повсеместно в C ++, но
IDispose
очень редко встречаются в .NET.источник