русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Свободная память


Дата добавления: 2015-06-12; просмотров: 413; Нарушение авторских прав


Если определить функции operator new() и operator delete(), управление памятью для класса можно взять в свои руки. Это также можно, (а часто и более полезно), сделать для класса, служащего базовым для многих производных классов. Допустим, нам потребовались свои функции размещения и освобождения памяти для класса employee ($$6.2.5) и всех его производных классов:

class employee {

// ...

public:

void* operator new(size_t);

void operator delete(void*, size_t);

};

 

void* employee::operator new(size_t s)

{

// отвести память в `s' байтов

// и возвратить указатель на нее

}

 

void employee::operator delete(void* p, size_t s)

{

// `p' должно указывать на память в `s' байтов,

// отведенную функцией employee::operator new();

// освободить эту память для повторного использования

}

Назначение до сей поры загадочного параметра типа size_t становится очевидным. Это - размер освобождаемого объекта. При удалении простого служащего этот параметр получает значение sizeof(employee), а при удалении управляющего - sizeof(manager). Поэтому собственные функции классы для размещения могут не хранить размер каждого размещаемого объекта. Конечно, они могут хранить эти размеры (подобно функциям размещения общего назначения) и игнорировать параметр size_t в вызове operator delete(), но тогда вряд ли они будут лучше, чем функции размещения и освобождения общего назначения.

Как транслятор определяет нужный размер, который надо передать функции operator delete()? Пока тип, указанный в operator delete(), соответствует истинному типу объекта, все просто; но рассмотрим такой пример:

class manager : public employee {

int level;

// ...

};

 

void f()

{

employee* p = new manager; // проблема

delete p;

}

В этом случае транслятор не сможет правильно определить размер. Как и в случае удаления массива, нужна помощь программиста. Он должен определить виртуальный деструктор в базовом классе employee:



class employee {

// ...

public:

// ...

void* operator new(size_t);

void operator delete(void*, size_t);

virtual ~employee();

};

Даже пустой деструктор решит нашу проблему:

employee::~employee() { }

Теперь освобождение памяти будет происходить в деструкторе (а в нем размер известен), а любой производный от employee класс также будет вынужден определять свой деструктор (тем самым будет установлен нужный размер), если только пользователь сам не определит его. Теперь следующий пример пройдет правильно:

void f()

{

employee* p = new manager; // теперь без проблем

delete p;

}

Размещение происходит с помощью (созданного транслятором) вызова

employee::operator new(sizeof(manager))

а освобождение с помощью вызова

employee::operator delete(p,sizeof(manager))

Иными словами, если нужно иметь корректные функции размещения и освобождения для производных классов, надо либо определить виртуальный деструктор в базовом классе, либо не использовать в функции освобождения параметр size_t. Конечно, можно было при проектировании языка предусмотреть средства, освобождающие пользователя от этой проблемы. Но тогда пользователь "освободился" бы и от определенных преимуществ более оптимальной, хотя и менее надежной системы.

В общем случае, всегда есть смысл определять виртуальный деструктор для всех классов, которые действительно используются как базовые, т.е. с объектами производных классов работают и, возможно, удаляют их, через указатель на базовый класс:

class X {

// ...

public:

// ...

virtual void f(); // в X есть виртуальная функция, поэтому

// определяем виртуальный деструктор

virtual ~X();

};



<== предыдущая лекция | следующая лекция ==>
Доступ к базовым классам | Виртуальные конструкторы


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.008 сек.