|
Программирование >> Оптимизация возвращаемого значения
применяться в приложениях, которые используют разделяемую память или ввод/ вывод с отображением в память, потому что объекты в таких приложениях размещаются по известным адресам памяти или тем, которые выделены при помощи специальных процедур. (Другой пример использования буферизованного оператора new см. в правиле 4.) Функция constructWidgetlnBuf f ег возвращает значение: new (buffer)Widget(widgetSize) Приведенное выражение поначалу может показаться вам немного странным, но на самом деле это просто форма оператора new с дополнительным аргументом (buffer), который передается для неявного вызова функции operator new. Здесь operator new помимо обязательного аргумента типа size t принимает дополнительный параметр типа void*, указывающий на область памяти, в которой должен разместиться создаваемый объект. Эта функция operator new представляет собой буферизованный оператор new, и ее реализация выглядит примерно так: void* operatornew(size t, void*location) { return location; Возможно, реализация выглядит проще, чем вы предполагали, но это все, что должен сделать буферизованный оператор new. Действительно, основная задача функции operator new состоит в том, чтобы найти область памяти для размещения объекта и вернуть указатель на нее. В сл5ае буферизованного оператора new вызывающий модуль уже знает, где должен быть расположен объект и чему должен быть равен указатель на содержащую его область памяти. Поэтому все, что должен сделать буферизованный оператор new, - это вернуть переданный ему указатель. (Имя неиспользованного (но обязательного) аргумента типа size t не указано, чтобы компиляторы не генерировали соответствующее предупреждение - см. правило 6.) Буферизованный оператор new является частью стандартной библиотеки C-I-+. Для его использования достаточно добавить директиву #include <new> (или, если ваши компиляторы пока не поддерживают имена файлов заголовков нового типа, <new.h>). Если на минуту отвлечься от буферизованного оператора new, то вы увидите, что взаимоотношения между оператором new и функцией operator new хотя и запутаны терминологически, по своей концепции довольно ясны. Для создания динамического объекта нужно использовать оператор new. Он и выделяет память, и вызывает конструктор объекта. Чтобы выделить память без вызова конструктора, нужно включить в код функцию operator new. Если для создания динамических объектов вам требуется какой-либо специальный механизм выделения памяти, придется написать собственную версию функции operator new. При вызове оператора new эта функция вызывается автоматически. Для создания объекта в области памяти, указатель на которую уже пол5ен, следует использовать буферизованный оператор new. Операторы Удаление объектов и освобождение памяти Чтобы избежать утечки ресурсов, каждый выделенный jacTOK памяти нужно после использования освободить. Функция operator delete соотносится со встроенным оператором delete так же, как функция operator new с оператором new. При компиляции следующего примера: string*ps, deleteps; Использование оператора delete. ваши компиляторы должны создать код не только для удаления объекта, на который указывает переменная ps, но и для освобождения памяти, занимаемой этим объектом. Освобождение памяти производит функция operator delete, обычно объявляемая так: voidoperatordelete(void*memory ToBeDeallocated) ; Следовательно, при компиляции deleteps; генерируется код, который примерно соответствует следующему: ps->~string(); Вызов деструктора объекта, operator delete(ps); Освободим память,занятую объектом. Отсюда следует, что если вы хотите работать только с неинициализированной памятью, нельзя работать с операторами new и delete. Вместо этого для выделения памяти следует использовать функцию operator new, а для освобождения памяти - функцию operator delete: void *buffer = Выделяемпамятьдля хранения operatornew(50*sizeof(char)); 50 символов; / / конструкторы не вызываем. operator delete(buffer); Освобождаемпамять; / / деструкторы не вызываем. Эти функции языка С++ эквивалентны функциям malloc и free. Если для создания объекта в некоторой области памяти был использован буферизованный оператор new, то для ее освобождения нельзя использовать оператор delete. Это связано с тем, что оператор delete вызывает для освобождения памяти функцию operator delete, но поскольку память, содержащая объект, не была выделена в результате вызова функции operator new; буферизованный оператор new просто вернул указатель, переданный ему в качестве аргумента. Причем неизвестно, откуда взялся этот указатель. Поэтому необходимо отменить действие конструктора явным вызовом деструктора объекта: void * mallocshared(size t size); Функции для выделения voidfreeShared(void*memory); и освобождения областей void *sharedMemorY = mallocShared{sizeof(Widget)); разделяемой памяти. Widget *pw= Как и в предыдущих примерах, ConstructWidgetlnBuffer(sharedMemory, 10); используется буферизованный / / оператор new. delete pw; He определено! sharedMemory создана функцией mallocShared, / / a не operator new. pw->~Widget(); Нормально, удаляет o6beKTWidget, на который указывает pw, ноне освобождает память, занятую Widget. freeShared(pw); Нормально,освобождает память, на / / которую указывает pw, но не вызывает деструктор. Итак, чтобы предотвратить утечки памяти, неинициализированную память, выделенную динамически (каким-либо специальным способом) и переданную буферизованному оператору new, следует освобождать. Массивы Все рассмотренные выше примеры относились к единичным объектам. А как насчет выделения памяти для массива? Что произойдет, например, здесь? string *ps = new string [10] ; Создаем массив объектов. Оператор new остался тем же самым, но поскольку создается массив объектов, его поведение слегка меняется. Во-первых, память выделяется не с использованием функции operator new, а при помощи эквивалентной функции для работы с массивами operator new[] (чаще ее называют функция new для массивов ). Аналогично функции operator new, функцию operator new[] можно перегрузить. Это позволяет контролировать выделение памяти для массивов таким же образом, как и для единичных объектов. Функция operator new [ ] была добавлена в стандарт языка С++ сравнительно недавно, и возможно, что ваши компиляторы ее не поддерживают. Тогда для выделения памяти массиву, независимо от типа его элементов, будет использован глобальный оператор new. Настройка механизма вьщеления памяти для массивов при этом усложняется, так как требует изменений в глобальной функции operator new. Не следует недооценивать данную задачу. По умолчанию глобальная функция operator new отвечает за все операции выделения памяти в программе, и вмешательство в ее механизм может привести к очень серьезным последствиям. Более того, существует только одна глобальная функция operator new нормального вида (то есть имеющая единственный аргумент типа size t), поэтому если вы перепишете ее, ваше программное обеспечение тут же станет несовместимым с любой библиотекой, использующей эту функцию. (См. также правило 27). Поэтому тем, чьи компиляторы не поддерживают функцию operator new [ ], не стоит пытаться разрабатывать собственные механизмы вьщеления памяти для массивов.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |