Динамическое распределение памяти
Рассмотрение особенностей использования оператора new. Определение способов и характеристика операторов для освобождения памяти. Исследование динамического распределения памяти в языке C+. Изучение основной концепции интеллектуальных указателей.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | реферат |
Язык | русский |
Дата добавления | 02.08.2015 |
Размер файла | 17,8 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
ДИНАМИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ ПАМЯТИ
Динамическое распределение памяти
Если ваши программа запрашивает память во время выполнения, она указывает требуемое количество памяти, а C++ возвращает указатель на эту память. C++ распределяет память из областей памяти, которые называются свободной памятью.
Основные концепции:
Чтобы запросить память во время выполнения, программа должны использовать оператор C++ new.
При использовании оператора new программы указывают количество требуемой памяти. Если оператор new может успешно выделить требуемый объем памяти, он возвращает указатель на начало области выделенной памяти.
Если оператор new не может удовлетворить запрос на память вашей программы (возможно, свободной памяти уже не осталось), он возвращает указатель NULL.
Чтобы позже освободить память, распределенную с помощью оператора new, программа должны использовать оператор C++ delete.
ИСПОЛЬЗОВАНИЕ ОПЕРАТОРА new
Оператор C++ new позволяет программам распределять память во время выполнения. Для использования оператора new необходимо указать количество байтов памяти, которое требуется программе. Предположим, например, что вашей программе необходим 50-байтный массив. Используя оператор new, вы можете заказать эту память, как показано ниже:
char *buffer = new char[50];
Говоря кратко, если оператор new успешно выделяет память, он возвращает указатель на начало области этой памяти. В данном случае, поскольку программа распределяет память для хранения массива символов, она присваивает возвращаемый указатель переменной, определенной как указатель на тип char. Если оператор new не может выделить запрашиваемый вами объем памяти, он возвратит NULL-указатель, который содержит значение 0.
Следующая программа ASK_MEM.CPP запрашивает у пользователя количество байт памяти, которое необходимо выделить, и затем распределяет память, используя оператор new:
#include <iostream.h>
void main(void)
{
int size;
char *pointer;
cout << "Введите размер массива, до 30000: ";
cin >> size;
if (size <= 30000)
{
pointer = new char[size];
if (pointer != NULL) cout << "Память выделена успешно" << endl;
else cout << "Невозможно выделить память" << endl;
}
}
Когда программы используют оператор new для динамического распределения памяти, то вполне вероятно, что они сами знают, сколько памяти необходимо выделить. Например, если программа распределяет память для хранения информации о служащих, она, возможно, сохранила количество служащих в файле. Следовательно, при запуске она может прочитать количество служащих из файла, а затем выделить соответствующее количество памяти.
Следующая программа NOMEMORY.CPP выделяет каждый раз память для 10000 символов до тех пор, пока оператор new не сможет больше выделить память из свободной памяти. Другими словами, эта программа удерживает выделенную память, пока не использует всю доступную свободную память. Если программа успешно выделяет память, она извещает об этом сообщением. Если память больше не может быть выделена, программа выводит сообщение об ошибке и завершается:
#include <iostream.h>
void main(void)
{
char * pointer;
do
{
pointer = new char[10000];
if (pointer != NULL) cout << "Выделено 10000 байт" << endl;
else cout << "Больше нет памяти" << endl;
} while (pointer 1= NULL);
}
Замечание: Если выработаете в среде MS-DOS, то свободная память исчерпается после того, как программа выделит 64 Кбайт, Большинство работающих в MS-DOS компиляторов C++ по умолчанию используют малую модель памяти, которая обеспечивает только 64 К6aйт свободной памяти. Аналогично, если вы используете среду MS-DOS, то наибольшая область памяти, к которой могут обратиться ваши программы, может быть ограничена 64Кбайт.
ОСВОБОЖДЕНИЕ ПАМЯТИ
Как вы знаете, оператор C++ new позволяет программам выделять память динамически во время выполнения. Если программе больше не нужна выделенная память, она должна ее освободить, используя оператор delete. Для освобождения памяти с использованием оператора delete вы просто указываете этому оператору указатель на данную область памяти, как показано ниже:
delete pointer;
Следующая программа DEL_MEM.CPP использует оператор delete для освобождения выделенной с помощью оператора new памяти:
#include <iostream.h>
#include <string.h>
void main(void)
{
char *pointer = new char[100];
strcpy(pointer, "Учимся программировать на языке C++");
cout << pointer << endl;
delete pointer;
}
По умолчанию, если программа не освобождает выделенную ей память до своего завершения, операционная система автоматически освобождает эту память после завершения программы. Однако если программа использует оператор delete для освобождения памяти по мере того, как она (память) становится ненужной, то эта память вновь становится доступной для других целей (возможно, для вашей программы, которая опять будет использовать оператор new, или для операционной системы).
Второй пример
Следующая программа ALLOCARR.CPP выделяет память для хранения массива из 1000 целочисленных значений. Затем она заносит в массив значения от 1 до 1000, выводя их на экран. Потом программа освобождает эту память и распределяет память для массива из 2000 значений с плавающей точкой, занося в массив значения от 1.0 до 2000.0:
#include <iostreain.h>
void main(void)
{
int *int_array = new int[1000];
float *float_array;
int i;
if (int_array 1= NULL)
{
for (i = 0; i < 1000; i++) int_array[i] = i + 1;
for (i = 0; i < 1000; i++) cout << int_array[i] << ' ';
delete int_array;
}
float_array = new float[2000];
if (float_array != NULL)
{
for (i = 0; i < 2000; i++) float_array[i] = (i + 1) * 1.0;
for (i = 0; i < 2000; i++) cout << float_array[i] << ' ' ;
delete float_array;
}
}
Как правило, программы должны освобождать память с помощью оператора delete по мере того, как память становится программам не нужна.
Динамическое распределение памяти в языке C: функции malloc() и free(). Отличия от С++
Язык C не содержит операторов new или delete. Вместо них в C используются библиотечные функции, предназначенные для выделения и освобождения памяти. В целях совместимости C++ по-прежнему поддерживает C-систему динамического распределения памяти и не зря: в C++-программах все еще используются C-ориентированные средства динамического распределения памяти. Ядро C-системы распределения памяти составляют функции malloc() и free(). Функция malloc() предназначена для выделения памяти, а функция free() -- для ее освобождения. Другими словами, каждый раз, когда с помощью функции malloc() делается запрос, часть свободной памяти выделяется в соответствии с этим запросом. При каждом вызове функции free() соответствующая область памяти возвращается системе. Любая программа, которая использует эти функции, должна включать заголовок <cstdlib>.
Функция malloc() имеет такой прототип.
void *malloc(size_t num_bytes);
Здесь num_bytes означает количество байтов запрашиваемой памяти.
представляет собой разновидность целочисленного типа без знака.) Функция malloc() возвращает указатель типа void, который играет роль обобщенного указателя. Чтобы из этого обобщенного указателя получить указатель на нужный вам тип, необходимо использовать операцию приведения типов. В результате успешного вызова функция malloc() возвратит указатель на первый байт области памяти, выделенной из “кучи”. Если для удовлетворения запроса свободной памяти в системе недостаточно, функция
malloc() возвращает нулевой указатель.
Функция free() выполняет действие, обратное действию функции malloc() в том, что она возвращает системе ранее выделенную ею память. После освобождения пмять можно снова использовать последующим обращением к функции malloc().
Функция free() имеет такой прототип.
void free(void *ptr);
Здесь параметр ptr представляет собой указатель на память, ранее выделенную с помощью функции malloc(). Никогда не следует вызывать функцию free() с недействительным аргументом; это может привести к разрушению списка областей памяти, подлежащих освобождению.
Использование функций malloc() и free() иллюстрируется в следующей программе.
// Демонстрация использования функций malloc() и free().
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
int *i;
double *j;
i = (int *) malloc(sizeof(int));
if(!i) {
cout << "Выделить память не удалось.\n";
return 1;
}
j = (double *) malloc(sizeof(double));
if(!j) {
cout << "Выделить память не удалось.\n";
return 1;
}
*i= 10;
*j = 100.123;
cout << *i << ' ' << *j;
// Освобождение памяти.
free(i);
free(j);
return 0;
}
Несмотря на то что функции malloc() и free() -- полностью пригодны для динамического распределения памяти, есть ряд причин, по которым в C++ определены собственные средства динамического распределения памяти.
Во-первых, оператор new автоматически вычисляет размер выделяемой области памяти для заданного типа, т.е. не нужно использовать оператор sizeof, а значит, налицо экономия в коде и трудовых затратах программиста. Но важнее то, что автоматическое вычисление не допускает выделения неправильного объема памяти.
Во-вторых, оператор new автоматически возвращает корректный тип указателя, что освобождает программиста от необходимости использовать операцию приведения типов.
В-третьих, используя оператор new, можно инициализировать объект, для которого выделяется память.
Наконец, программист может создать собственные версии операторов
new и delete.
Из-за возможной несовместимости не следует смешивать функции
malloc() и free() с операторами new и delete в одной программе.
Концепция интеллектуальных указателей
Интеллектуальный указатель (англ. smart pointer) -- класс (обычно шаблонный), имитирующий интерфейс обычного указателя и добавляющий некую новую функциональность, например проверку границ при доступе или очистку памяти. оператор память язык указатель
Владеющие указатели
Чаще всего интеллектуальный указатель инкапсулирует семантику владения ресурсом. В таком случае он называется владеющим указателем.
Владеющие указатели применяются для борьбы с утечками памяти и висячими ссылками. Утечкой памяти называется ситуация, когда в программе нет ни одного указателя, хранящего адрес объекта, созданного в динамической памяти. Висячей ссылкой (англ. Dangling pointer) называется указатель, ссылающийся на уже удалённый объект. Семантика владения для динамически созданных объектов означает, что удаление или присвоение нового значения указателю будет согласовано с временем жизни объекта.
Простые владеющие указатели
Такие указатели при присвоении нового значения или удалении сами удаляют объект. Их недостатком являются трудности с передачей объекта за пределы области видимости указателя.
Указатели с подсчётом ссылок
Такие обычно используются с объектами, имеющими специальные операции «увеличить число ссылок» и «уменьшить число ссылок». Чаще всего такие объекты унаследованы от специального класса или интерфейса.
При появлении новой ссылки на объект вызывается операция «увеличить число ссылок», а при уничтожении -- «уменьшить число ссылок». Если в результате операции «уменьшить число ссылок» число ссылок на объект становится равным нулю, то объект удаляется.
Такая методика называется автоматическим подсчётом ссылок. Она согласует число указателей, хранящих адрес объекта, с числом ссылок, хранящимся в объекте, а при достижении этим числом нулевого значения приводит к удалению объекта. Её преимуществами являются относительно высокие надёжность, быстродействие и простота реализации в C++. Недостатком является усложнение использования в случае возникновения циклических ссылок (необходимость пользоваться "слабыми ссылками").
Проблема циклических ссылок
Предположим, есть два объекта и в каждом из них по владеющему указателю. Указателю в первом объекте присвоим адрес второго объекта, а указателю во втором -- адрес первого объекта. Если теперь всем внешним (то есть не хранящимся внутри этих объектов) указателям на два данных объекта присвоить новые значения, то указатели внутри объектов по-прежнему будут владеть друг другом и будут оставаться в памяти. В результате возникнет ситуация, когда к объектам невозможно получить доступ, то есть утечка памяти.
Проблема циклических ссылок решается либо путем соответствующего проектирования структур данных, либо использованием сборки мусора, либо использованием двух видов ссылок: сильные (владеющие) и слабые (невладеющие).
Шаблоны интеллектуальных указателей в С++
Используя конструкцию класса, мы можем реализовать более "умный" указатель, чем встроенный. В этом случае мы получаем возможность управления поведением указателей:
при создании и уничтожении;
при копировании и присваивании;
при разыменовании.
По сложившейся традиции такие указатели называются "интеллектуальными" {по англ. smart pointers).
"Интеллектуальные" указатели обычно реализуются в виде шаблона, т, к. они должны быть максимально типизированы: параметр шаблона определяет тип указываемого объекта. Пример реализации в виде шаблона:
template <class T> class SmartPtr {
public:
explicit (T* p) :
aa^r.Pcr(const SmartPtr &ref);
-SmarrPtr ();
SmartPtr Т& operator* () const
{return *pointer;
}
T* operator->() const { return pointer;}
private: T* pointer;
}
Конструктор по умолчанию отсутствует, чтобы нельзя было создать "пустой" указатель. Конструктор преобразования объявлен как explicit, чтобы запретить неявные преобразования встроенных типов указателей в "интеллектуальные". Конструктор копирования и операция присваивания сделаны открытыми, но при необходимости мы легко можем запретить эти действия, перенеся объявления в приватную часть класса.
Несмотря на отсутствие конструктора по умолчанию, мы все-таки можем создать нулевой указатель, например:
SmartPtr<double> ip(0);
Тогда деструктор обязательно должен проверять этот факт.
SmartPtr<T>::-SmartPtr()
{ if delete pointer; }
Однако и наши операции разыменования тоже должны учитывать возможное нулевое значение. Чтобы не завершать программу аварийно, можно объявить в приватной части фиктивный элемент-константу, который нужно инициализировать в конструкторе. Тогда операция разыменования * может возвращать ссылку на фиктивный элемент, а операция -> будет возвращать его адрес.
T& operator*() const { if (!pointer) return pointed; else return *pointer;
}
T* operator->() const { if (!pointer) return pointed; else return *pointer;
}
Однако нам еще потребуется проверка на о самого "интеллектуального" указателя, чтобы в программе можно оыло использовать обычные конструкции вроде такой:
if (!ip)
Операция проверки на ноль
bool operator!() const { return pointer ==0; }
Осталось разобраться с коированием и присваиванием. Именно эти операции доставляют больше всего "головной боли" программистам. Вариантов реализации достаточно много, мы рассмотрим разрушающее копирование и присваивание (destructive copy), которое реализовано в стандартной библиотеке шаблонов STL.
auto_ptr
В STL есть шаблон "интеллектуального" указателя, который называется auto_ptr.
Копирование и присваивание в шаблоне auto_ptr:
template <class T>
auto_ptr<T>: : auto_ptr(auto_ptr<T> &rhs)
{ pointer = rhs.pointer;
rhs.pointer = 0; // прежний владелец -больше не владелец
}
template <class T>
auto_ptr<T>& auto_ptr<T>::operator=(auto_ptr<T> &rhs)
{ if (this != rhs) delete pointer; // удаляем прежний объект
pointer = rhs.pointer; // вступили во владение;
rhs.pointer = 0; // прежний владелец -- больше не владелец
Return *this;
}
auto_ptr<T>::~auto_ptr() { delete pointer;}
Здесь сразу бросается в глаза то, что передаваемые по ссылке параметры -не константы. Так и должно быть, чтобы можно было обнулить указатель параметра. Вторая особенность -- тривиальный конструктор, который не проверяет указатель на ноль. Этого и не требуется делать, поскольку конструктор копирования и операция присваивания гарантируют "владение" объектом.
Отрицательные стороны. Например, такие указатели не всегда возможно передавать в качестве параметров по значению. Так как при передаче по значению происходит копирование, то исходный указатель перестает быть владельцем объекта. Поэтому в большинстве случаев auto_ptr надо передавать по ссылке. Однако возвращать созданный внутри функции указатель вполне безопасно.
Таким образом, "интеллектуальный" указатель, реализованный подобным способом, не похож на обычные объекты: его копии не эквивалентны. Поэтому такие указатели нельзя использовать в качестве элементов стандартных контейнеров.
Размещено на Allbest.ru
...Подобные документы
Модель памяти как набор опций компилятора, ее виды в BC++2.0, размеры и взаимное расположение. Назначение сегментных регистров в различных моделях памяти, порядок просмотра переменных. Основные и дополнительные функции динамических переменных в памяти.
лабораторная работа [28,4 K], добавлен 06.07.2009Схема распределения памяти, соответствующая пользовательской трактовке распределения памяти. Перемещение с помощью таблицы сегментов. Аппаратная поддержка сегментного распределения памяти. Сегментно-страничная организация памяти с двухуровневой схемой.
лекция [1,5 M], добавлен 24.01.2014Применение программы-имитатора динамического распределения оперативной памяти, выполнение ее на ОС Windows 7 в интегрированной среде. Разработка приложений с графическим интерфейсом Delphi XE3. Автоматическая загрузка, исполнение и добавление процессов.
курсовая работа [284,7 K], добавлен 12.01.2015Распределение оперативной памяти фиксированными, динамическими и перемещаемыми разделами. Распределение с использованием внешней памяти. Принципы рaботы матричного принтера. Проектирование символов и разработка программы, реализующей их вывод на печать.
курсовая работа [241,3 K], добавлен 01.07.2011Объем двухпортовой памяти, расположенной на кристалле, для хранения программ и данных в процессорах ADSP-2106x. Метод двойного доступа к памяти. Кэш-команды и конфликты при обращении к данным по шине памяти. Пространство памяти многопроцессорной системы.
реферат [28,1 K], добавлен 13.11.2009Стратегии размещения информации в памяти. Алгоритмы распределения адресного пространства оперативной памяти. Описание характеристик модели и ее поведения, классов и элементов. Выгрузка и загрузка блоков из вторичной памяти. Страничная организация памяти.
курсовая работа [708,6 K], добавлен 31.05.2013Сравнение различных способов обхода данных. Заполнение массива для случайного обхода. Изучение понятия кэш-памяти, ее основных размеров и функций. Оптимальный и неоптимальный алгоритм умножения двух матриц с точки зрения порядка обхода данных в памяти.
презентация [94,7 K], добавлен 02.06.2013Составление алгоритмов и написание программ циклической структуры с использованием векторов, указателей и векторов указателей на вектор на языке C++. Статическое и динамическое распределение памяти. Функция ввода и обработки элементов вектора или матрицы.
контрольная работа [210,5 K], добавлен 25.03.2015Характеристика флэш-памяти, особого вида энергонезависимой перезаписываемой полупроводниковой памяти. Исследование особенностей организации флэш-памяти. Общий принцип работы ячейки. Обзор основных типов карт памяти. Защита информации на флеш-накопителях.
презентация [9,3 M], добавлен 12.12.2013Внутренний кэш. Смешанная и разделенная кэш-память. Статическая и динамическая память. TLB как разновидность кэш-памяти. Организация кэш-памяти. Отображение секторов ОП в кэш-памяти. Иерархическая модель кэш-памяти. Ассоциативность кэш-памяти.
курсовая работа [229,1 K], добавлен 04.11.2006Откачка и подкачка, схема. Смежное распределение памяти. Аппаратная поддержка регистров перемещения и границы. Стратегии динамического распределения памяти. Внешняя и внутренняя фрагментация. Схема адресной трансляции по двухуровневой таблице страниц.
лекция [2,0 M], добавлен 24.01.2014Распределение виртуальной памяти. Страничная и сегментная организации виртуальной памяти. Сегментно-страничная организация виртуальной памяти. Преобразование виртуального адреса в физический. Упрощение адресации памяти клиентским программным обеспечением.
курсовая работа [440,7 K], добавлен 04.03.2014Сравнительный анализ статической и динамической памяти. Быстродействие и потребление энергии статической памятью. Объем памяти микросхем. Временные диаграммы чтения и записи памяти. Микросхемы синхронной и асинхронной памяти. Режимы модулей памяти.
презентация [114,2 K], добавлен 27.08.2013Классификация компьютерной памяти. Использование оперативной, статической и динамической оперативной памяти. Принцип работы DDR SDRAM. Форматирование магнитных дисков. Основная проблема синхронизации. Теория вычислительных процессов. Адресация памяти.
курсовая работа [1,5 M], добавлен 28.05.2016Проблемы, возникающие при работе с динамическими переменными, их решение. Алгоритм Дойча-Шорра-Уэйта. Структура памяти и стратегия ее перераспределения. Главная идея, лежащая в основе "методов близнецов". Разбивка памяти на блоки и их упорядочение.
курсовая работа [57,0 K], добавлен 29.01.2010Обобщение основных видов и назначения оперативной памяти компьютера. Энергозависимая и энергонезависимая память. SRAM и DRAM. Триггеры, динамическое ОЗУ и его модификации. Кэш-память. Постоянное запоминающее устройство. Флэш-память. Виды внешней памяти.
курсовая работа [1,7 M], добавлен 17.06.2013Хранение различной информации как основное назначение памяти. Характеристика видов памяти. Память типа SRAM и DRAM. Кэш-память или сверхоперативная память, ее специфика и области применения. Последние новинки разработок в области в оперативной памяти.
презентация [2,1 M], добавлен 01.12.2014Динамическое распределение памяти. Анализ виртуальной памяти, алгоритм ее обращения, общие принципы защиты. Страничная организация. Особенности переключения в мультизадачный режим. Режим системного управления. Расширение размера адресного пространства.
презентация [1,3 M], добавлен 14.12.2013Организация памяти компьютера и простые схемы управления ею. Принципы связывания адресов. Динамическое распределение и свопинг. Сегментная и сегментно-страничная организация памяти. Выталкивание редко используемой страницы. Описание работы с программой.
курсовая работа [3,1 M], добавлен 19.01.2016Разработка алгоритма работы и структуры контроллера кэш-памяти с полностью ассоциативным отображением основной памяти. Представление операционной и управляющей частей черного ящика устройства. Схема алгоритма контроллера кэш на уровне микроопераций.
курсовая работа [1,0 M], добавлен 19.03.2012