Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 34
Текст из файла (страница 34)
Но в этом случае память динамически не распределяется. Откровенно говоря, в программировании обычно не приняло пользоваться оператором пен вместе с типами значений. "Сборка мусора" и применение деструкторов Как было показано выше, при использовании оператора пеы свободная память для создаваемых объектов динамически распределяется из доступной буферной области оперативной памяти. Разумеется, оперативная память не бесконечна, и поэтому свободно доступная память рано нли поздно исчерпывается. Это может привести к новому сбою в работе программы из-за нехватки свободной памяти для создания требуемого объекта.
Именно по этой причине одной из главных функций любой схемы динамического распределения памяти является освобождение свободной памяти от неиспользуемых объектов, чтобы сделать ее доступной для последующего перераспределения. Во многих языках программирования освобождение распределенной ранее памяти осуществляется вручную.
Например, в С++ для этой цели служит оператор с)е1еге. Но в С() применяется другой, более надежный подход: сборка мусора". Система "сборки мусора" в С(г освобождает память от лишних объектов автоматически, действуя подспудно, незаметно и без всякого вмешательства со стороны программиста.
"Сборка мусора" происходит следующим образом. Если ссылки на объект отсутствуют, то такой объект считается больше ненужным, и занимаемая им память в итоге освобождается и накапливается. Эта утилизированная память может быть затем распределена для других объектов. "Сборка мусора" происходит лишь время от времени по ходу выполнения программы. Она не состоится только потому, что существует один или более объектов, которые больше не используются. Следовательно, нельзя заранее знать или предположить, когда именно произойдет "сборка мусора". Деструкторы В языке С() имеется возможность определить метод, который будет вызываться непосредственно перед окончательным уничтожением объекта системой "сборки мусора".
Такой метод называется деаяруюаором и может использоваться в ряде особых случаев, чтобы га- 168 Часть (. Язык С№ рантировать четкое окончание срока действия объекта. Например, деструктор может быть использован для гарантированного освобождения системного ресурса, задействованного освобождаемым объектом.
Следует, однако, сразу же подчеркнуть, что деструкторы — весьма специфические средства, применяемые только в редких, особых случаях. И, как правило, они не нужны. Но здесь они рассматриваются вкратце ради полноты представления о возможностях языка С№. Ниже приведена общая форма деструктора. -имя класса () ( // код деструктора ) где имч класса означает имя конкретного класса.
Следовательно, деструктор объявляется аналогично конструктору, за искзючением того, что перед его именем указывается знак "гильда" (-). Обратите внимание на то, что у деструктора отсутствуют возвратцаемый тип и передаваемые ему аргументы. Для того чтобы добавить деструктор в класс, достаточно включить его в класс в качестве члена. Он вызывается всякий раз, когда предполагается утилизировать объект его класса. В деструкторе можно указать те действия, которые следует выполнить перед тем, как уничтожать объект. Следует, однако, иметь в виду, что деструктор вызывается непосредственно перед "сборкой мусора". Он не вызывается, например, в тот момент, когда переменная, содержащая ссылку на объект, оказывается за пределами области действия этого объекта.
(В этом отношении деструкторы в С№ отличаются от деструкторов в С++, где они вызываются в тот момент, когда объект оказывается за пределами области своего действия.) Это означает, что заранее нельзя знать, когда именно следует вызывать деструктор. Кроме того, программа может завершиться до того, как произойдет "сборка мусора", а следовательно, деструктор может быть вообще не вызван. Ниже приведен пример программы, демонстрирующий применение деструктора. В этой программе создается и уничтожается большое число объектов. В какой-то момент по ходу данного процесса активизируется "сборка мусора" и вызываются деструкторы для уничтожения ненужных объектов.
// Продемонстрировать применение деструктора. ояъпд Зувсежт о1авя Пеякгоос ( роъ11о 1пк риъ11с Певсгосс(гпс 1) х=ъ; // Вызывается при утилизации объекта. -пеяггоог() ( Сопво1е.игъгеъ№пе("Уничтожить " + х) ) // Создает объект и тут же уничтожает его. роо11о то16 Пепегасог(ъпс 1) ( Глава В. Введение а классы, объекты и методы 169 пеякгиск о = пен пеякгиск(1) ) ) 01аяя пеякгпсппешо ( якак1с уоаб Маап() ( 1пс сопок) пезкгисс оЬ = пен пеякгиск(0) /* Л теперь создать большое число объектов. В какой-то момент произойдет "сборка мусора".
Примечание: для того чтобы актизизирозать "сборку мусора", возможно, придется увеличить число создаваемых объектов. */ Гог(соппк=1т соппк < 100000) соппкт+) оЬ.пепегаког(сопок)) Сопяо1е.игтсе01пе("Готово(")т ) Эта программа работает следующим образом. Конструктор инициализирует переменную х известным значением. В данном примере переменная х служит в качестве идентификатора объекта. А деструктор выводит значение переменной х, когда объект утилизируется. Особый интерес вызывает метод пепегасог (), который создает и тут же уничтожает объект типа Реяьгпсс. Сначала в классе пеясгпсспешо создается исходный объект оЬ типа Резггпсг, а затем осуществляется поочередное создание и уничтожение 100 тыс.
объектов. В разные моменты этого процесса происходит "сборка мусора". Насколько часто она происходит — зависит от нескольких факторов, в том числе от первоначального объема свободной памяти, типа используемой операционной системы и т.д. Тем ие менее в какой-то момент начинают появляться сообщения, формируемые деструктором. Если же оии ие появятся до окончания программы, т.е. до того момента, когда будет выдано сообщение 'Тотовор', попробуйте увеличить число создаваемых объектов, повысив предельное количество подсчитываемых шагов в цикле гог.
И еще одно важное замечание: метод иг1ьеьвпе() вызывается в деструкторе -Пезггпсг () исключительно ради наглядности данного примера его применения. Как правило, деструктор должен воздействовать только иа переменные экземпляра, определенные в его классе.
В силу того что порядок вызова деструкторов ие определен точно, их ие следует применять для выполнения действий, которые должны происходить в определенный момент выполнения программы. В то же время имеется возможность запрашивать "сборку мусора", как будет показано в части 11 этой книги при рассмотрении библиотеки классов СФ. Тем ие менее инициализация "сборки мусора" вручную в большинстве случаев ие рекомендуется, поскольку это может привести к снижению эффективности программы.
Кроме того, у системы "сборки мусора" имеются свои особенности — даже если запросить "сборку мусора" явным образом, все равно нельзя заранее знать, когда именно будет утилизировав коикретиый объект. 170 часть ), язык С№ Ключевое слово Иьхв Прежде чем завершать эту главу, необходимо представить ключевое слово г)г15. Когда метод вызывается, ему автоматически передается ссылка на вызывающий объект, т.е. тот объект, для которого вызывается данный метод. Эта ссылка обозначается ключевым словом гп15. Следовательно, ключевое слово с)г15 обозначает именно тот объект, по ссылке на который действует вызываемый метод. Для того чтобы стало яснее назначение ключевого слова гЫэ, рассмотрим сначала пример программы, в которой создается класс несс, инкапсулирующий ширину и высоту прямоугольника и включающий в себя метод Агеа (), возвращающий площадь прямоугольника.
оагпЧ зуагещ) с1ааа Несо ( РоЫ№с 1пс Х1НГП! роЫгс гпс Не1ЧПГ; рпЫгс Несс(гпс н, гпс П) ( Хгпсв = н; Не1двс = П; риЫ1с гпс Игеа() ( гесогп Хгг)ГП * Негдьс," ) с1ааа Паеиесс ( ясас1с чо1о Маги() ( Несо г1 = лен Несо(4, 5) васс г2 = пен Несо(7, 9) Сопао1е.нг1сеьвпе("Площадь прямоугольника г1: г1.Агеа())) Сопао1е.нг1сеьвпе("Площадь прямоугольника г2: г2.Агеа()); Как вам должно уже быть известно, другие члены класса могут быть доступны непосредственно без дополнительного уточнения имени объекта или класса. Поэтому оператор гесогп Х1г)ГП * Негдвс) в методе Агеа () означает, что копии переменных Х1бгь и не1ялг, связанные с вызывающим объектом, будут перемножены, а метод возвратит их произведение.
Но тот же самый оператор можно написать следующим образом: гесогп ГП1а.н1ось * ГП1я.не1цПГ; В этом операторе ключевое слово СП15 обозначает объект, для которого вызван метод Агеа () . Следовательно, в выражении гп15. Х1сгв делается ссылка на копию переменной х1г(гп данного объекта, а в выражении гп15. не1д)гг — ссылка на копию перемен- Глава б. Введение в классы, объекты и методы 171 ной не1оьс этого же объекта.
Так, если бы метод Агеа () был вызван для объекта х, то ключевое слово СЬ1я в приведенном выше операторе обозначало бы ссылку на объект х. написание оператора без ключевого слова сь1я представляет собой не более чем сокращенную форму записи. Ключевое слово Сная можно также использовать в конструкторе. В этом случае оно обозначает объект, который конструируется. Например, следующие операторы в методе несс () Ы1ПСЬ = нт НеьдЬС = )ы можно было бы написать таким образом; СЬ1я.н1с(СЬ = сьья.ие19нс = )и Разумеется, такой способ записи не дает в данном случае никаких преимушеств. Ради примера ниже приведен весь класс несс, написанный с использованием ссылки Сная.
ияъпч Яуясещ; с 1 а я я на с С ( рпЬ11с 1пС И1т)СЬт ривъвс 1пС Не19ЬС; рпв11с Неск(1пС н, 1пС Ь) ( СЬ1я.н1с(СЬ = «; СЬ1Я.НЕ19ЬС = )П ) рпвъъс ъпС Агеа() ( гекпгп СЬ1я.н1т)СЬ * Спья.неъчпкт ) ) с1аяя Пяереск ( якаккс то1С Накп () ( аесс г1 = пен Неск (4, 5) т несс г2 = пен несс (7, 9) т Сопяо1е.нгъьеь1пе("Площадь прямоугольника г1: г1.Агеа () ) т Сопяо1е.ыг1Сеъ1пе("Площадь прямоугольника с2: г2.Агеа () ) т В действительности ключевое слово Снйя не используется приведенным вьпне способом в программировании на С№, поскольку это практически ничего не дает, да и стандартная форма записи намного проще и понятнее.
Тем не менее ключевому слову сь1я можно найти не одно полезное применение. Например, в синтаксисе С№ допускается называть параметр или локальную переменную тем же именем, что и у переменной экземпляра. В этом случае имя локальной переменной скрывает переменную экземпляра.