Почему структуры не могут иметь деструкторов?

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

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


person Valentin Kuzub    schedule 26.11.2011    source источник
comment
Я бы не стал спрашивать об этом на собеседовании, так как мне нравится задавать вопросы, которые в основном относятся к реальному опыту работы, как прошлому, так и будущему. Если вы хотите увидеть, как кто-то рассуждает в неясных угловых случаях, или посмотреть, как они реагируют на такой вопрос в интервью, то этот вопрос может вписаться в большую группу вопросов. В противном случае это в основном мелочи. Я бы дал им баллы за то, что они хорошо обдумали это, и за то, что они указали, что это то, с чем вы, вероятно, не столкнетесь в дикой природе. Упоминание этого бессмысленного вопроса могло принести баллы, в зависимости от того, как они это сделали.   -  person Merlyn Morgan-Graham    schedule 26.11.2011
comment
Я знаю место, где задают этот вопрос на собеседовании. Я думал, что есть разные типы дорог, по которым можно пойти, отвечая на него. Мне нравится ответ, за который в настоящее время проголосовали. Кроме того, насколько я знаю, этот интервьюер не задает вопросов, касающихся lambdas/linq, но он задает этот довольно бесполезный вопрос (имхо). Особенно потому, что я знаю, что домен очень далек от уровня структур, и я считаю, что в этом проекте менее 0,5% структур, фактическое число, вероятно, еще меньше. Такой странный вопрос, действительно, тоже не уверен, что они там пытаются проверить.   -  person Valentin Kuzub    schedule 26.11.2011
comment
PS: учитывая приведенное выше описание, я сомневаюсь, что упоминание о том, что это бессмысленный вопрос, принесет нам баллы на таком собеседовании :) следующий вопрос, конечно же, - действительно ли мы хотим там работать.   -  person Valentin Kuzub    schedule 26.11.2011
comment
Да, с этим интервьюером может быть нехорошо указывать, что он спрашивает мелочи. Со мной как интервьюером это было бы. Вот что я хотел сказать :) Что касается вопросов по лямбда и Linq, я бы не стал их избегать, но и не стал бы спрашивать о них, если кандидат не проявил интереса. Языковые возможности великолепны, и важно оценить их интерес к языковым особенностям. Но я бы подождал, пока они не покажут, что знают и заинтересованы в этих языковых функциях, прежде чем я напрямую спрошу о них. То же самое с шаблонами проектирования, внедрением зависимостей, различными библиотеками .Net и многим другим.   -  person Merlyn Morgan-Graham    schedule 26.11.2011
comment
хм, становится все интереснее. Не могли бы вы уточнить, что кандидат проявляет интерес. Допустим, кандидат сидит напротив вас, как обычно, немного напряженный. Как он начинает проявлять интерес к таким разным темам, как DI, linq, паттерны, если вы сами не спросите его об этом?   -  person Valentin Kuzub    schedule 26.11.2011
comment
@ValentinKuzub: Вы заставите его/ее рассказать о недавних проектах, в которых они участвовали. Хотя возможно, что их недавний проект касался именно этих вещей (LINQ, шаблонов и т. д.), они неизбежно будут включать что-то стоит задать дополнительные вопросы о том, был ли кандидат искренне заинтересован в проекте.   -  person Joel B Fant    schedule 26.11.2011
comment
Я бы не всегда. Некоторым позициям нужны теплые тела, некоторым нужны хорошие командные игроки, некоторым нужны люди, которые будут расширять границы вашей команды. Так что все зависит от кандидата и должности. Если кто-то зажат непропорционально своему уровню, вы можете рассмотреть его для менее критической позиции или можете полностью дисквалифицировать его на основе мягких навыков. Отчасти ваша работа состоит в том, чтобы расслабить их — у этой улицы есть две стороны :) Кроме того, как сказал Джоэл, с добавлением того, что можно спрашивать о внеклассных интересах программирования, особенно если это есть в их резюме.   -  person Merlyn Morgan-Graham    schedule 26.11.2011


Ответы (4)


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

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

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

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

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

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

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

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

person BrendanMcK    schedule 26.11.2011
comment
Потрясающий ответ! На самом деле я всегда ищу такие ответы на вопросы такого типа, дизайнерское решение, а не окончательное решение. +1. - person OmarOthman; 26.11.2011
comment
Деструкторы имели бы смысл для структур тогда и только тогда, когда структуры имели бы средства переопределения конструктора копирования по умолчанию. - person supercat; 21.12.2011
comment
@supercat Я абсолютно согласен. Теперь вопрос, почему бы не допустить этого? В моем случае я хочу реализовать удобную систему подсчета ссылок для использования в пулах объектов. (Почему? Потому что в приложениях реального времени, таких как игры, недетерминированная сборка мусора может привести к смерти. Пул объектов может гарантировать, что, если не будет серьезного нехватки памяти или какого-либо явного этапа загрузки, память будет использоваться повторно, и никогда освобожден.) - person Domi; 13.02.2016
comment
@Domi: Если у структур не может быть конструкторов, то массивы можно создавать, просто заполняя новое выделение нулем. Поддержка конструкторов структур значительно усложнила бы построение массива, особенно учитывая возможность того, что (1) структуры могут быть вложенными, и (2) конструкторы могут дать сбой в процессе инициализации массива. - person supercat; 13.02.2016
comment
Теперь у вас есть две структуры с одинаковыми внутренними полями, и обе они будут пытаться очистить один и тот же объект. Сначала произойдет один, и поэтому код, который впоследствии использует другой, начнет загадочно давать сбой - если деструкторы просто вызывают Dispose(false), а Dispose() можно вызывать несколько раз, не вызывая проблем. Разве это не означает, что финализаторы можно вызывать несколько раз, не вызывая проблем? - person David Klempfner; 02.05.2018
comment
@DavidKlempfner см. ObjectDisposedException - person mBardos; 25.03.2021

От Джона Джаггера:

«У структуры не может быть деструктора. Деструктор — это просто замаскированное переопределение object.Finalize, а структуры, являющиеся типами значений, не подлежат сборке мусора».

person Cameron Skinner    schedule 26.11.2011
comment
Коротко и по делу. Ваш ответ также является единственным ответом, в котором ошибочно не упоминается стек. - person ; 26.11.2011
comment
Почему бы не запускать финализатор, когда структура выходит за пределы области видимости, если это локальная переменная, или когда она является частью объекта, а объект очищается сборщиком мусора? Если структура может реализовать IDisposable, почему у нее не может быть финализатора? - person David Klempfner; 02.05.2018
comment
Разве структуры не собираются мусором, если они содержатся в объекте, который должен находиться в куче? - person David Klempfner; 02.05.2018
comment
@Backwards_Dave нет. Объекты в куче подвергаются сборке мусора. Если у вас есть экземпляр класса C { int x; } вы не говорите, что целое число x подвергается сборке мусора. - person Warty; 13.10.2019
comment
@Warty, что происходит с целым числом, которое находится в куче, когда его объект, содержащийся внутри, подвергается сборке мусора? - person David Klempfner; 25.03.2021
comment
Это немного педантично, ха-ха, GCing применяется ко всем выделениям GC. Отдельный байт в распределении GC не освобождается отдельно, освобождается выделение GC. Если вы читаете здесь, например, github.com/ Сборка мусора dotnet/docs/blob/main/docs/standard/ применяется ко всем объектам. Вроде как, если вы делаете X = malloc(sizeof(someStruct)) then free(X), вы не освобождаете отдельное поле F внутри X; вы освобождаете блок памяти X или, альтернативно, блок памяти, содержащий F, известный как X; странно говорить, что ты освобождаешь F :P - person Warty; 26.03.2021

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

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

person supercat    schedule 28.06.2012

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

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

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

person aevanko    schedule 26.11.2011
comment
хорошо, этот тип дороги по определению педантичен, но я не уверен, что это лучшая линия для интервью. Однако я вижу достоинства этого подхода в некоторых случаях. Когда нас спрашивают, почему параллельные прямые не пересекаются? ответ по определению кажется гораздо более подходящим, чем здесь я считаю. - person Valentin Kuzub; 26.11.2011
comment
Я согласен, что формулировка по определению хороша, поэтому я сделал твик :) - person aevanko; 26.11.2011
comment
Проблема здесь в том, что на многие вопросы можно ответить таким образом, однако часто существует и лучший ответ. И хотя это будет абсолютно правильный ответ, в большинстве случаев он не принесет нам очков. - person Valentin Kuzub; 26.11.2011
comment
Деструкторы не уничтожают экземпляры классов. Их роль, несмотря на их неудачное название, заключается в том, чтобы позволить классам выполнять действия, которые должны быть выполнены и которые только они способны выполнить. Например, если кто-то попросит систему открыть файл, система создаст дескриптор файла и передаст его запрашивающему с обещанием, что те, у кого есть дескриптор, могут иметь исключительный доступ к файлу до тех пор, пока кто-то с дескриптором не скажет, что такой доступ запрещен. требуется дольше. Класс File, который содержит такой дескриптор, будет обязан гарантировать, что система будет уведомлена, когда он больше не нужен. - person supercat; 21.12.2011
comment
В противном случае у системы не было бы возможности узнать, что ни у кого еще нет копии дескриптора файла, и, таким образом, файл оставался бы открытым бесконечно долго, исключительно для объекта, которого больше не существует. Как ни странно, деструкторы не уничтожают классы, а откладывают их уничтожение до тех пор, пока все их дела не будут приведены в порядок. - person supercat; 21.12.2011
comment
supercat, спасибо за добавленную информацию. Так вы говорите, что Microsoft ошибается в своем собственном определении? (Честно говоря, меня бы это не шокировало). - person aevanko; 22.12.2011
comment
На веб-сайте Microsoft есть много рекомендаций, которые, возможно, когда-то имели ценность, но в настоящее время являются далеко не лучшим способом ведения дел. Finalize было гораздо более информативным названием, чем cleanup, хотя NotifyOfAbandonment было бы даже лучше. - person supercat; 28.12.2011