Статические объекты создаются при запуске программы в сегменте данных и существуют до закрытия. Конструкторы для таких объектов вызываются неявно в порядке поступления объектов на вход компоновщика. Деструкторы вызываются при окончании работы программы в порядке обратном порядку вызова конструктора.
Локальные объекты создаются в стеке в момент входа в блок или функцию и уничтожатся при выходе оттуда. Конструкторы вызываются неявно в момент определения объекта при каждом очередном входе в блок программы в порядке определения. Деструкторы для каждого объекта вызываются неявно при выходе из блока в порядке обратном порядку вызова конструктора. В стек могут создаваться временные объекты, необходимые для вычисления выражений и вызова функций. Порядок вызова конструкторов определяется порядком вычисления. Деструкторы для временных объектов выполняются по окончанию операторов, в которых потребовались временные переменные.
Динамические объекты создаются, инициализируются и уничтожатся по требованию программиста при помощи операторов new и delete. Операция new кроме выделения памяти определяет вызов соответствующего конструктора. Delete – соответствующий деструктор. Для объектов пользовательского типа надо пользоваться только new и delete, а не fmalloc, потому что malloc не вызывает конструктора. То же самое происходит и при delete.
Допускается создание и инициализация статических и динамических массивов из объекта класса. Синтаксис напоминает создание обыкновенных
Point2D P1[3]={Point2D(2,4),Point2D(1,4),Point2D(4,6)};
Point2D P[3]={5,3,1};
Point2D P1[3]={Point2D(4),Point2D(1),Point2D(6)};
Point2D P1[3]={Point2D(4),Point2D(1,4),6}; //для первого вызывается с одним параметром, потом с двумя параметров, а потом конструктор по умолчанию
На первый взгляд, кажется, что для каждого элемента массива создается временный объект, а потом массив инициализируется этими временными объектами. На самом деле никаких лишних действий компилятор не производит.
Массивы объектов класса
Допускается создание и инициализация статических и автоматических массивов из объектов класса. Синтаксически инициализация напоминает синтаксис для стандартных типов данных.
Point2D P1[3]={Point2D(2,4),Point2D(3,3),Point2D(4,6)};
Point2D P2[3]={Point2D(5),Point2D(4),Point2D(3)};
Point2D P3[3]={5,4,3};
Point2D P4[3]={Point2D(4),5,Point2D(3,1)};
На первый взгляд кажется, что для каждого элемента массива создается временный элемент типа Point2D, а потом массив инициализируется этим объектами, с помощью конструктора копий. На самом деле лишних действий нет. Вызываются лишь конструкторы для областей памяти, соответствующих элементов массива.
Если у класса конструктор операции new [], можно создать массив в динамической области памяти. Инициализация такого массива не допустима.
Point2D *pArray= new Point2D[20];
...........
delete [] pArray;
Операция new гарантирует вызов конструктора для каждого объекта массива. Чтобы можно было описать массив объектов класса с конструктором, этот класс должен иметь стандартный конструктор, т.е. конструктор, вызываемый без параметров. Например, в соответствии с определением
table tbl[10];будет создан массив из 10 таблиц, каждая из которых инициализируется вызовом table::table(15), поскольку вызов table::table() будет происходить с фактическим параметром 15.
В описании массива объектов не предусмотрено возможности указать параметры для конструктора. Если члены массива обязательно надо инициализировать разными значениями, то начинаются трюки с глобальными или статическими членами.
Когда уничтожается массив, деструктор должен вызываться для каждого элемента массива. Для массивов, которые размещаются не с помощью new, это делается неявно. Однако для размещенных в свободной памяти массивов неявно вызывать деструктор нельзя, поскольку транслятор не отличит указатель на отдельный объект массива от указателя на начало массива, например:
void f()
{ table* t1 = new table; table* t2 = new table[10]; delete t1; // удаляется одна таблица delete t2; // неприятность: // на самом деле удаляется 10 таблиц}В данном случае программист должен указать, что t2 - указатель на массив:
void g(int sz){ table* t1 = new table; table* t2 = new table[sz]; delete t1; delete[] t2;} Функция размещения хранит число элементов для каждого размещаемого массива. Требование использовать для удаления массивов только операцию delete[] освобождает функцию размещения от обязанности хранить счетчики числа элементов для каждого массива. Исполнение такой обязанности в реализациях С++ вызывало бы существенные потери времени и памяти и нарушило совместимость с С.