Почему структуры не могут иметь деструкторов? - PullRequest
23 голосов
/ 26 ноября 2011

Какой самый лучший ответ на собеседовании на такой вопрос, как вы думаете?

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

Ответы [ 4 ]

51 голосов
/ 26 ноября 2011

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

(Не зацикливайтесь на слове «деструктор»)здесь, мы в основном говорим о магическом методе для структур, который вызывается автоматически, когда переменная выходит из области видимости. Другими словами, языковая функция, аналогичная деструкторам C ++.)

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

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

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

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

И просто, чтобы сделать вещи немного более запутанными, как указывал один из других ответовСтруктуры не просто существуют как локальные объекты.С местными жителями область видения хороша и хорошо определена;но структуры также могут быть членами объекта класса.Когда в этом случае должен вызываться «деструктор»?Конечно, вы можете сделать это, когда класс контейнера будет завершен;но теперь у вас есть механизм, который ведет себя очень по-разному в зависимости от того, где находится структура: если структура является локальной, она запускается сразу в конце области видимости;если структура находится внутри класса, она запускается лениво ... Так что если вы действительно заботитесь о том, чтобы какой-то ресурс в одной из ваших структур был очищен в определенное время, и если ваша структура могла бы в конечном итоге стать членомкласс, вам, возможно, понадобится что-то явное, например IDisposable / using (), чтобы убедиться, что ваши основы покрыты.

Так что, хотя я не могу утверждать, что говорю от имени языковых дизайнеров, я могу сделатьДовольно неплохо догадаться, что одна из причин, по которой они решили не включать такую ​​функцию, заключается в том, что это будет червячная банка, и они хотели сохранить C # достаточно простым.

31 голосов
/ 26 ноября 2011

From Jon Jagger :

"Структура не может иметь деструктор. Деструктор является просто переопределением object.Finalize в скрытой форме, и структуры, являющиеся типами значений, не подлежатв сборку мусора. "

0 голосов
/ 28 июня 2012

Каждый объект, кроме массивов и строк, хранится в куче одинаково: заголовок, который предоставляет информацию о свойствах «объекта» (его тип, используется ли он какими-либо активными блокировками монитора, имеет ли он не подавленный метод Finalize и т. д.) и его данные (то есть содержимое всех полей экземпляра типа (общие, частные и защищенные, смешанные с полями базового класса перед полями производного типа). Потому что каждая куча У объекта есть заголовок, система может взять ссылку на любой объект и узнать, что это такое, и что должен делать с ним сборщик мусора. Если система имеет список всех объектов, которые были созданы и имеют * Метод 1002 *, он может исследовать каждый объект в списке, посмотреть, не отменен ли его метод Finalize, и действовать соответствующим образом.

Структуры хранятся без заголовка; структура типа Point с двумя целочисленными полями просто сохраняется как два целых числа. Хотя возможно иметь ref для структуры (такая вещь создается, когда структура передается как параметр ref), код, который использует ref, должен знать, какой тип структуры ref указывает, поскольку ни ref, ни сама структура не содержат эту информацию. Кроме того, объекты кучи могут быть созданы только сборщиком мусора, что гарантирует, что любой созданный объект всегда будет существовать до следующего цикла GC. Пользовательский код, напротив, может создавать и уничтожать структуры самостоятельно (часто в стеке); если код создает структуру вместе с ref и передает ее ref в вызываемую подпрограмму, то нет никакого способа, которым код может разрушить структуру (или сделать что-либо вообще, в этом отношении) до вызываемой подпрограммы возвращается, поэтому структура гарантированно существует по крайней мере до тех пор, пока не будет вызвана вызываемая подпрограмма. С другой стороны, после того, как вызванная подпрограмма завершится, ref, который она получила, следует считать недействительным, поскольку вызывающая сторона может в любой момент уничтожить структуру.

0 голосов
/ 26 ноября 2011

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

Ссылка: http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

По собственным словам Microsoft: "Destructors are used to destruct instances of classes." поэтому глупо спрашивать: «Почему вы не можете использовать деструктор ( что-то, что не является классом )?»^^

...