Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Вопрос 47. Динамические переменные. Выделение и освобождение памяти при выполнении программы.Содержание книги
Похожие статьи вашей тематики
Поиск на нашем сайте
Динамические переменные – это переменные, которые создаются (и уничтожаются) во время выполнения программы. В зависимости от того, кто отвечает за работу с такими переменными – компилятор или программист – различают языки с динамическим или статическим управлением памятью. Динамические переменные создаются в куче (heap) - специально отведенной для этой цели области оперативной памяти, которая располагается между стеком и статической областью команд и данных. Для создания и уничтожения динамических переменных в С++ используются операторы new и delete, соответственно. Значением оператора new является адрес созданной переменной, а в случае неудачи NULL. Созданная переменная не имеет имени и связь с нею можно осуществить только одним способом – присвоив ее адрес указателю соответствующего типа. При уничтожении динамической переменной ее адрес (т.е. значение соответствующего указателя) передается оператору delete. Область видимости динамической переменной совпадает с областью видимости указателя на нее, а время жизни заключено между действием оператора new и оператора delete. Динамическое выделение памяти необходимо для эффективного использования памяти компьютера. Например, мы написали какую-то программку, которая обрабатывает массив. При написании данной программы необходимо было объявить массив, то есть задать ему фиксированный размер (к примеру, от 0 до 100 элементов). Тогда данная программа будет не универсальной, ведь может обрабатывать массив размером не более 100 элементов. А если нам понадобятся всего 20 элементов, но в памяти выделится место под 100 элементов, ведь объявление массива было статическим, а такое использование памяти крайне не эффективно. В С++ операции new и delete предназначены для динамического распределения памяти компьютера. Операция new выделяет память из области свободной памяти, а операция delete высвобождает выделенную память. Выделяемая память, после её использования должна высвобождаться, поэтому операции new и delete используются парами. Даже если не высвобождать память явно, то она освободится ресурсами ОС по завершению работы программы. Рекомендую все-таки не забывать про операцию delete.
Операция new создает объект заданного типа, выделяет ему память и возвращает указатель правильного типа на данный участок памяти. Если память невозможно выделить, например, в случае отсутствия свободных участков, то возвращается нулевой указатель, то есть указатель вернет значение 0. Выделение памяти возможно под любой тип данных: int, float, double, char и т. д.
Разработаем программу, в которой будет создаваться динамическая переменная.
В строке 10 показан способ объявления и инициализации девяткой динамического объекта, все, что нужно так это указать значение в круглых скобочках после типа данных. Результат работы программы показан на рисунке 1. Рисунок 1 - Динамическая переменная Как было сказано раньше, массивы также могут быть динамическими. Чаще всего операции new и delete применяются, для создания динамических массивов, а не для создания динамических переменных. Рассмотрим фрагмент кода, создания одномерного динамического массива.
После того как динамический массив стал ненужным, нужно освободить участок памяти, который под него выделялся.
После оператора delete ставятся квадратные скобочки, которые говорят о том, что высвобождается участок памяти, отводимый под одномерный массив.
Третий способ выделения памяти в языке Си++ – динамический. Память для величины какого-либо типа можно выделить, выполнив операцию new. В качестве операнда выступает название типа, а результатом является адрес выделенной памяти. long* lp; // создать новое целое число lp = new long; Complex* cp; // создать новый объект типа Complex cp = new Complex; Созданный таким образом объект существует до тех пор, пока память не будет явно освобождена с помощью операции delete. В качестве операнда deleteдолжен быть задан адрес, возвращенный операцией new: delete lp; delete cp; Динамическое распределение памяти используется, прежде всего, тогда, когда заранее неизвестно, сколько объектов понадобится в программе и понадобятся ли они вообще. С помощью динамического распределения памяти можно гибко управлять временем жизни объектов, например выделить память не в самом начале программы (как для глобальных переменных), но, тем не менее, сохранять нужные данные в этой памяти до конца программы. Если необходимо динамически создать массив, то нужно использовать немного другую форму new: new int[100]; В отличие от определения переменной типа массив, размер массива в операции new может быть произвольным, в том числе вычисляемым в ходе выполнения программы. (Напомним, что при объявлении переменной типа массив размер массива должен быть константой.) Освобождение памяти, выделенной под массив, должно быть выполнено с помощью следующей операции delete delete [] address; Выделение памяти под строки В следующем фрагменте программы мы динамически выделяем память под строку переменной длины и копируем туда исходную строку // стандартная функция strlen подсчитывает // количество символов в строке int length = strlen(src_str); // выделить память и добавить один байт // для завершающего нулевого байта char* buffer = new char[length + 1]; strcpy(buffer, src_str); // копирование строки Операция new возвращает адрес выделенной памяти. Однако нет никаких гарантий, что new обязательно завершится успешно. Объем оперативной памяти ограничен, и может случиться так, что найти еще один участок свободной памяти будет невозможно. В таком случае new возвращает нулевой указатель (адрес 0). Результат new необходимо проверять: char* newstr; size_t length = 4; newstr = new (std::nothrow) char[length]; if (newstr == NULL) { // проверить результат // обработка ошибок } // память выделена успешно Рекомендации по использованию указателей и динамического распределения памяти Указатели и динамическое распределение памяти – очень мощные средства языка. С их помощью можно разрабатывать гибкие и весьма эффективные программы. В частности, одна из областей применения Си++ – системное программирование – практически не могла бы существовать без возможности работы с указателями. Однако возможности, которые получает программист при работе с указателями, накладывают на него и большую ответственность. Наибольшее количество ошибок в программу вносится именно при работе с указателями. Как правило, эти ошибки являются наиболее трудными для обнаружения и исправления. Приведем несколько примеров. Использование неверного адреса в операции delete. Результат такой операции непредсказуем. Вполне возможно, что сама операция пройдет успешно, однако внутренняя структура памяти будет испорчена, что приведет либо к ошибке в следующей операции new, либо к порче какой-нибудь информации. Пропущенное освобождение памяти, т.е. программа многократно выделяет память под данные, но "забывает" ее освобождать. Такие ошибки называют утечками памяти. Во-первых, программа использует ненужную ей память, тем самым понижая производительность. Кроме того, вполне возможно, что в 99 случаях из 100 программа будет успешно выполнена. Однако если потеря памяти окажется слишком большой, программе не хватит памяти под какие-нибудь данные и, соответственно, произойдет сбой. Запись по неверному адресу. Скорее всего, будут испорчены какие-либо данные. Как проявится такая ошибка – неверным результатом, сбоем программы или иным образом – предсказать трудно Примеры ошибок можно приводить бесконечно. Общие их черты, обуславливающие сложность обнаружения, это, во-первых, непредсказуемость результата и, во-вторых, проявление не в момент совершения ошибки, а позже, быть может, в том месте программы, которое само по себе не содержит ошибки (неверная операцияdelete – сбой в последующей операции new, запись по неверному адресу – использование испорченных данных в другой части программы и т.п.). Отнюдь не призывая отказаться от применения указателей (впрочем, в Си++ это практически невозможно), мы хотим подчеркнуть, что их использование требует внимания и дисциплины. Несколько общих рекомендаций.
Ссылки Ссылка – это еще одно имя переменной. Если имеется какая-либо переменная, например Complex x; то можно определить ссылку на переменную x как Complex& y = x; и тогда x и y обозначают одну и ту же величину. Если выполнены операторы x.real = 1; x.imaginary = 2; то y.real равно 1 и y.imaginary равно 2. Фактически, ссылка – это адрес переменной (поэтому при определении ссылки используется символ & -- знак операции взятия адреса), и в этом смысле она сходна с указателем, однако у ссылок есть свои особенности. Во-первых, определяя переменную типа ссылки, ее необходимо инициализировать, указав, на какую переменную она ссылается. Нельзя определить ссылку int& xref; можно только int& xref = x; Во-вторых, нельзя переопределить ссылку, т.е. изменить на какой объект она ссылается. Если после определения ссылки xref мы выполним присваивание xref = y; то выполнится присваивание значения переменной y той переменной, на которую ссылается xref. Ссылка xref по-прежнему будет ссылаться на x. В результате выполнения следующего фрагмента программы: int x = 10; int y = 20; int& xref = x; xref = y; x += 2; cout << "x = " << x << endl; cout << "y = " << y << endl; cout << "xref = " << xref << endl; будет выведено: x = 22 y = 20 xref = 22 В-третьих, синтаксически обращение к ссылке аналогично обращению к переменной. Если для обращения к атрибуту объекта, на который ссылается указатель, применяется операция ->, то для подобной же операции со ссылкой применяется точка ".". Complex a; Complex* aptr = &a; Complex& aref = a; aptr->real = 1; aref.imaginary = 2; Как и указатель, ссылка сама по себе не имеет значения. Ссылка должна на что-то ссылаться, тогда как указатель должен на что-то указывать.
|
||||||||||||||
Последнее изменение этой страницы: 2016-08-15; просмотров: 1483; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.23.92.50 (0.009 с.) |