Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 129
Текст из файла (страница 129)
Преимущество применения оператора всас)ка11ос заключается, в частности, в том, что в этом случае не нужно беспокоиться об очистке памяти средствами "сборки мусора". Ниже приведен пример применения оператора в Сасйа11ос. // Продемонстрировать применение оператора всасха11ос. па1по Зуакеик с1ава Пвезсасха11ос ( ппааке акаскс то1п' Ма1п() ( 1пс* ркка = акасха11ос 1пс[3]з ркка[0] = 1к ркка[1] = 2к рсгв[2] = 3; Гог(кпк 1=0) 1 < 3; 1++) Сопао1е.нг1кеьйпе(река[1]); Вот к какому результату приводит выполнение кода из данного примера: Создание буферов фиксированного размера Ключевое слово 21хес[ находит еще одно применение при создании одномерных массивов фиксированного размера. В документации на С№ такие массивы называются буферами фиксированного размера.
Такие буферы всегда являются членами структуры. Они 670 Часть !. Язык С№ предназначены для создания структуры, в которой содержатся элементы массива, образующие буфер. Когда элемент массива включается в состав структуры, в ней, как правило, хранится лишь ссылка на этот массив. Используя буфер фиксированного размера, в структуре можно разместить весь массив. В итоге получается структура, пригодная в тех случаях, когда важен ее размер, как, например, в многоязыковом программировании, при согласовании данных, созданных вне программы на С№, или же когда требуется неуправляемая структура, содержащая массив.
Но буферы фиксированного размера можно использовать только в небезопасном коде. Для создания буфера фиксированного размера служит следующая общая форма; Г1хеб тнп нмя буфера)размер] Строка длиной 80 байтов, состоящая из 8-разрядных символов в коде АЗС)! Числовое значение типа бооЫе длиной 8 байтов Числовое значение типа 1опч длиной 8 байтов Мате Ва1апсе 10 В программе на С++ каждая структура содержит массив маме, тогда как в программе на С№ в такой структуре хранится лишь ссылка на массив.
Поэтому для правильного представления данных из этой структуры в С№ требуется буфер фиксированного размера, как показано ниже. // использовать буфер фиксированного размера. дпяаге ясгосс г1хебвапхкесогб ! роЬ11с Гьхеб Ьуве Мазе)80]1 // создать буфер фиксированного размера роЫгс бооЬ1е Ва1апсе; рпЫгс 1опд 10у ) Когда буфер фиксированного размера используется вместо массива Маме, каждый экземпляр структуры Г1хес]нап)гпесогг) будет содержать все 80 байтов массива маме.
Именно таким образом структура и организована в программе-на С++. Следовательно, общий размер структуры р1хебвапкнесогб окажется равным 96, те. сумме ее членов. Ниже приведена программа, демонстрирующая этот факт. // Продемонстрировать применение буфера фиксированного размера. пяьпд зуядесн // Создать буфер фиксированного размера.
ппяасе ядгпсд Г1хебвапккесогб ! роЫьс аахен Ьуде Мазе]80]; рпЫьс бооЬ1е Ва1апсе; где тип обозначает тип данных массива; имя буфера — конкретное имя буфера фиксированного размера; размер — количество элементов, образующих буфер. Буферы фиксированного размера могут указываться только в структуре. Для того чтобы стала очевиднее польза от буферов фиксированного размера, рассмотрим ситуацию, в которой программе ведения счетов, написанной на С++, требуется передать информацию о банковском счете. Допустим также, что учетная запись каждого счета организована так, как показано ниже.
Глава 20. Небезопасный код, указатели, обнуллемые типы и разные ключевые слова 671 роЬ11с 1опд тп) ) с1азз Гвхебз1кеВовкег ( // Пометить метод Мавп() как небезопасный. опваке зсас1с токб Магп() ( Сопзо1е. Иг1сеькпе ( "Размер структуры ГгхебВапниесогсп в1кеок(кгхебВапхвесогб))т Эта программа дает следующий результат: Размер структуры Р1хебВапнвесогсп 96 Размер структуры Р1хебвап)гпесогс) оказывается в точности равным сумме ее члеиов, ио так бывает далеко ие всегда со структурами, содержащими буферы фиксированного размера. Ради повышения эффективности кода общая длина структуры может быть увеличена для выравнивания по четной границе, например по границе слова.
Поэтому общая длина структуры может оказаться иа несколько байтов больше, чем сумма ее членов, даже если в ией содержатся буферы фиксированного размера. Как правило, аналогичное выравнивание длины структуры происходит и в С++. Следует, однако, иметь в виду возможиые отличия в этом отношении. И наконец, обратите внимание иа то, как в данной программе создается буфер фиксированного размера вместо массива Метле. ровггс Егхеб Ьусе Мазе[ВО]' // создать буфер фиксированного размера Как видите, размер массива указывается после его имени.
Такое обозначение обычно принято в С++ и отличается в объявления массивов в С№. В данном операторе распределяется 80 байтов памяти в каждом объекте типа Рйхебвапккесогг). Обнуляемые типы Начиная с версии 2.0 в язык С№ внедрено средство, обеспечивающее изящное решение типичной и ие очень приятной задачи распознавания и обработки полей, ие содержащих значения, т.е. неинициализированных полей.
Это средство называется обнуляемым шиполс Для того чтобы стала более понятной суть данной задачи, рассмотрим пример простой базы данных заказчиков, в которой хранится запись с именем, адресом, идеитификациоииым номером заказчика, номером счета-фактуры и текущим остатком иа счету. В подобной ситуации может быть вполне создан элемент данных заказчика, в котором одно или несколько полей ие ииициализироваиы.
Например, заказчик может просто запросить каталог продукции, и в этом случае номер счета-фактуры ие потребуется, а зиачит, его поле окажется неиспользованным. Раньше для обработки неиспользуемых полей приходилось применять заполняющие значения или дополнительные поля, которые просто указывали, используется поле или иет. Безусловно, заполияюшие значения пригодны лишь в том случае, если оии подставляются вместо значения, которое в противном случае окажется недействительным, ио так бывает далеко ие всегда.
А дополнительные поля, указывающие, используется поле 672 Часть!. Язык С№ или нет, пригодны во всех случаях, но их ввод и обработка вручную доставляют немало хлопот. Оба этих затруднения позволяет преодолеть обнуляемый тип. Основы применения обнуляемых типов Обнуляемый тип — это особый вариант типа значения, представленный структурой. Помимо значений, определяемых базовым типом, обнуляемый тип позволяет хранить пустые значения (пп11). Следовательно, обнуляемый тип имеет такой же диапазон представления чисел и характеристики, как и его базовый тип.
Он предоставляет дополнительную возможность обозначить значение, указывающее на то, что переменная данного типа не инициализирована. Обнуляемые типы являются обьектами типа зузсет. нп11аЬ1е<т>, где т — тип значения, которое не должно быть обнуляемым. г гомимг Обнуллемые эктгваленты могут быть только у типов значений. Обнуляемый тип может быть указан двумя способами. Во-первых, объекты типа нп11аЬ1е<т>, определенного в пространстве имен зуэсет, могут быть объявлены явным образом. Так, в приведенном ниже примере создаются обнуляемые переменные типа 1пС и Ьоо1. зуесем.но11аьье<1пс> <попс; Зуэьеп.ип11аЬ1е<Ьоо1> боне? И во-вторых, обнуляемый тип объявляется более кратким и поэтому чаще используемым способом с указанием знака ? после имени базового типа.
В приведенном ниже примере демонстрируется более распространенный способ объявления обнуляемых переменных типа Ьпх и Ьоо1. 1пс? Ьоо1? бове; Когда в коде применяются обнуляемые типы, создаваемый обнуляемый объект обычно выглядит следующим образом: ьпс? соппп = по11; В данной строке кода переменная соппс явно инициализируется пустым значением (пп11). Это вполне соответствует принятому правилу: прежде чем использовать переменную, ей нужно присвоить значение. В данном случае присваиваемое значение означает, что переменная не определена. Значение может быть присвоено обнуляемой переменной обычным образом, поскольку преобразование базового типа в обнуляемый определено заранее.
Например, в следующей строке кода переменной соппс присваивается значение 100: соопь = 100г Определить, имеет ли переменная обнуляемого типа пустое или конкретное значение, можно двумя способами. Во-первых, можно проверить переменную на пустое значение. Так, если переменная соопс объявлена так, как показано выше, то в следующей строке определяется, имеет ли эта переменная конкретное значение: 1ггсонпь != пн11) // переменная имеет значение Если переменная соопС не является пустой, то она содержит конкретное значение. Глава 20.
Небезопасный код, указатели, обнулнеыые типы и разные ключевые слова 673 И во-вторых, можно воспользоваться доступным только для чтения свойством Навуа1пе типа Хп11аЬ1е<т>, чтобы определить, содержит ли переменная обнуляемого типа конкретное значение. Это свойство показано ниже. Ьоп1 НавЧа1пе Свойство навча1ое возвращает логическое значение сгпе, если экземпляр объекта, для которого оно вызывается, содержит конкретное значение, а иначе оно возвращает логическое значение уа1зе. Ниже приведен пример, в котором конкретное значение обнуляемого объекта соппг определяется вторым способом с помощью свойства НазЧа1пе. 11(соппк.иавЧа1пе) // переменная имеет значение Если обнуляемый объект содержит конкретное значение, то получить это значение можно с помощью доступного только для чтения свойства Ча1пе типа хи11аЬ1ест>: Т Ча1пе Свойство Ча1пе возвращает экземпляр обнуляемого объекта, для которого оно вызывается.
Если же попытаться получить с помощью этого свойства значение пустой переменной, то в итоге будет сгенерировано исключение яувсещ. 1пча11к(Орегасйопкхсергкоп. Кроме того, значение экземпляра обнуляемого объекта можно получить путем приведения к его базовому типу. В следующей программе демонстрируется основной механизм обращения с обнуляемым типом: // Продемонстрировать применение обнуляемого типа. пв1пч Зувкещт с1авв НЧ11аЬ1епещо ( вкаккс то1к( маке() ( кпвт сопок = пп11т 1Г(соппг.иавуа1пе) Сопво1е.нг1геьапе("Переменная соппг имеет " + "следующее значение: " т сопок.уа1пе); е1ве Сопвп1е.нгасеьапе("Переменная соппс не имеет значение") сопок = 100к 11(спало.иавЧа1пе) сопво1е.хг1сеькпе("переменная соппс имеет " + "следующее значение: " ь соппс.ча1пе)т е1ве Сопво1е.нг1кеьлпе("Переменная соппс не имеет значение")к Вот к какому результату приводит выполнение этой программы: Переменная спало не имеет значения Переменная сопок имеет следующее значение: 100 6Н часть (.
язык Са Применение обнуляемых обьектов в выражениях Обнуляемый объект может использоваться в тех выражениях, которые являются действительными для его базового типа. Более того, обнуляемые объекты могут сочетаться с необнуляемыми объектами в одном выражении. И это вполне допустимо благодаря предопределенному преобразованию базового типа в обнуляемый. Когда обнуляемые и необнуляемые типы сочетаются в одной операции, ее результатом становится значение обнуляемого типа.
В приведенной ниже программе демонстрируется применение обнуляемых типов в выражениях. // Использовать обнуляемые объекты в выражениях. пв1пд Зувсеют с1авв Но11аю1еоещо ( вьасгс чо10 Маги() ( гпг? сопле = по11? 1пс? геви1Г = пп11; гпс гпсг = 10) // переменная гпсг не является обнуляемой // переменная геви1Г содержит'пустое значение, // переменная оказывается соопс пустой.