Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / C / C++ / Введение в язык C++ / Классы /
8  Perl
8  PHP
8  JavaScript
8  HTML
8  DHTML
8  XML
8  CSS
8  C / C++
8  Pascal и Delphi
8  Турбо Ассемблер
8  MySQL
8  CASE-технологии
8  Алгоритмы
8  Python
8  Обратная связь
8  Гостевая книга
Новости о мире


Конструкторы и Деструкторы - Программирование от RIN.RU
Конструкторы и Деструкторы



Вектора Объектов Класса


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


Например:


table tblvec[10];


будет ошибкой, так как для table::table() требуется целый параметр. Нет способа задать параметры конструктора в описании вектора. Чтобы можно было описывать вектор таблиц table, можно модифицировать описание table (см. этот раздел) например так:


class table {
// ...
void init(int sz); // как старый конструктор
public:
table(int sz) // как раньше, но без по умолчанию
{ init(sz); }
table() // по умолчанию
{ init(15); }
}


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


Например:


void f()
{
table* t1 = new table;
table* t2 = new table[10];
delete t1; // одна таблица
delete t2; // неприятность: 10 таблиц
}


В этом случае длину вектора должен задавать программист:


void g(int sz)
{
table* t1 = new table;
table* t2 = new table[sz];
delete t1;
delete[] t2;
}


Но почему же компилятор не может найти число элементов вектора из объема выделенной памяти? Потому, что распределитель свободной памяти не является частью языка и может быть задан программистом.


Небольшие Объекты


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


Рассмотрим класс name, который использовался в примерах table. Его можно было бы определить так:


struct name {
char* string;
name* next;
double value;




name(char*, double, name*);
~name();
};


Программист может воспользоваться тем, что размещение и освобождение объектов заранее известного размера может обрабатываться гораздо эффективнее (и по памяти, и по времени), чем с помощью общей реализации new и delete. Общая идея состоит в том, чтобы предварительно разместить "куски" из объектов name, а затем сцеплять их, чтобы свести выделение и освобождение к простым операциям над связанным списком. Переменная nfree является вершиной списка неиспользованных name:


const NALL = 128;
name* nfree;


Распределитель, используемый операцией new, хранит размер объекта вместе с объектом, чтобы обеспечить правильную работу операции delete. С помощью распределителя, специализированного для типа, можно избежать этих накладных расходов. Например, на моей машине следующий распределитель использует для хранения name 16 байт, тогда как для стандартного распределителя свободной памяти нужно 20 байт. Вот как это можно сделать:


name::name(char* s, double v, name* n)
{
register name* p = nfree; // сначала выделить




if (p)
nfree = p->next;
else { // выделить и сцепить
name* q = (name*)new char[ NALL*sizeof(name) ];
for (p=nfree=&q[NALL-1]; qnext = p-1;
(p+1)->next = 0;
}


this = p; // затем инициализировать
string = s;
value = v;
next = n;
}


Присвоение указателю this информирует компилятор о том, что программист взял себе управление, и что не надо использовать стандартный механизм распределения памяти. Конструктор name::name() обрабатывает только тот случай, когда name размещается посредством new, но для большей части типов это всегда так. В этом отделе объясняется, как написать конструктор для обработки как размещения в свободной памяти, так и других видов размещения.
Заметьте, что просто как


name* q = new name[NALL];


память выделять нельзя, поскольку это приведет к бесконечной рекурсии, когда new вызовет name::name().


Освобождение памяти обычно тривиально:


name::~name()
{
next = nfree;
nfree = this;
this = 0;
}


Присваивание указателю this 0 в деструкторе обеспечивает, что стандартный распределитель памяти не используется.


<<<  НазадВперед  >>>
 1  2  3  4 


 8  Комментарии к статье  8 8  Обсудить в чате

8  В тему

Знакомство и краткий обзор

Классы и Члены

Интерфейсы и Реализации

Друзья и Объединения

 
  
  
    Copyright ©  RIN 2003 - 2004      * Обратная связь