Бьерн Страуструп. Язык программирования С++


Конструкторы и деструкторы



бет44/124
Дата16.07.2016
өлшемі3.27 Mb.
#204081
түріКнига
1   ...   40   41   42   43   44   45   46   47   ...   124

5.5 Конструкторы и деструкторы


Если у класса есть конструктор, он вызывается всякий раз при

создании объекта этого класса. Если у класса есть деструктор,

он вызывается всякий раз, когда уничтожается объект этого класса.

Объект может создаваться как:

[1] автоматический, который создается каждый раз, когда его

описание встречается при выполнении программы, и уничтожается

по выходе из блока, в котором он описан;

[2] статический, который создается один раз при запуске программы

и уничтожается при ее завершении;

[3] объект в свободной памяти, который создается операцией new

и уничтожается операцией delete;

[4] объект-член, который создается в процессе создания другого

класса или при создании массива, элементом которого он

является.

Кроме этого объект может создаваться, если в выражении явно

используется его конструктор ($$7.3) или как временный объект

($$R.12.2). В обоих случаях такой объект не имеет имени. В следующих

подразделах предполагается, что объекты относятся к классу с

конструктором и деструктором. В качестве примера используется

класс table из $$5.3.1.

5.5.1 Локальные переменные


Конструктор локальной переменной вызывается каждый раз, когда при

выполнении программы встречается ее описание. Деструктор локальной

переменной вызывается всякий раз по выходе из блока, где она

была описана. Деструкторы для локальных переменных вызываются в

порядке, обратном вызову конструкторов при их создании:


void f(int i)

{

table aa;



table bb;

if (i>0) {

table cc;

// ...


}

// ...


}
Здесь aa и bb создаются (именно в таком порядке) при каждом вызове

f(), а уничтожаются они при возврате из f() в обратном порядке -

bb, затем aa. Если в текущем вызове f() i больше нуля, то cc

создается после bb и уничтожается прежде него.

Поскольку aa и bb - объекты класса table, присваивание aa=bb

означает копирование по членам bb в aa (см. $$2.3.8). Такая

интерпретация присваивания может привести к неожиданному (и обычно

нежелательному) результату, если присваиваются объекты класса,

в котором определен конструктор:
void h()

{

table t1(100);



table t2 = t1; // неприятность

table t3(200);


t3 = t2; // неприятность

}
В этом примере конструктор table вызывается дважды: для t1 и t3.

Он не вызывается для t2, поскольку этот объект инициализируется

присваиванием. Тем не менее, деструктор для table вызывается три

раза: для t1, t2 и t3! Далее, стандартная интерпретация

присваивания - это копирование по членам, поэтому перед выходом

из h() t1, t2 и t3 будут содержать указатель на массив имен, память

для которого была выделена в свободной памяти при создании t1.

Указатель на память, выделенную для массива имен при создании

t3, будет потерян. Этих неприятностей можно избежать (см. $$1.4.2

и $$7.6).

5.5.2 Статическая память


Рассмотрим такой пример:


table tbl(100);
void f(int i)

{

static table tbl2(i);



}
int main()

{

f(200);



// ...

}
Здесь конструктор, определенный в $$5.3.1, будет вызываться дважды:

один раз для tbl и один раз для tbl2. Деструктор table::~table()

также будет вызван дважды: для уничтожения tbl и tbl2 по выходе

из main(). Конструкторы глобальных статических объектов в файле

вызываются в том же порядке, в каком встречаются в файле

описания объектов, а деструкторы для них вызываются в обратном

порядке. Конструктор локального статического объекта вызывается,

когда при выполнении программы первый раз встречается определение

объекта.


Традиционно выполнение main() рассматривалось как выполнение

всей программы. На самом деле, это не так даже для С. Уже

размещение статического объекта класса с конструктором и (или)

деструктором позволяет программисту задать действия, которые

будут выполняться до вызова main() и (или) по выходе из main().

Вызов конструкторов и деструкторов для статических объектов

играет в С++ чрезвычайно важную роль. С их помощью можно обеспечить

соответствующую инициализацию и удаление структур данных,

используемых в библиотеках. Рассмотрим . Откуда

берутся cin, cout и cerr? Когда они инициализируются? Более

существенный вопрос: поскольку для выходных потоков используются

внутренние буфера символов, то происходит выталкивание этих

буферов, но когда? Есть простой и очевидный ответ: все действия

выполняются соответствующими конструкторами и деструкторами до

запуска main() и по выходе из нее (см. $$10.5.1). Существуют альтернативы

использованию конструкторов и деструкторов для инициализации и

уничтожения библиотечных структур данных, но все они или очень

специализированы, или неуклюжи, или и то и другое вместе.

Если программа завершается обращение к функции exit(), то

вызываются деструкторы для всех построенных статических объектов.

Однако, если программа завершается обращением к abort(), этого

не происходит. Заметим, что exit() не завершает

программу немедленно. Вызов exit() в деструкторе может привести

к бесконечной рекурсии. Если нужна гарантия, что будут уничтожены

как статические, так и автоматические объекты, можно воспользоваться

особыми ситуациями ($$9).

Иногда при разработке библиотеки бывает необходимо или просто

удобно создать тип с конструктором и деструктором только для

одной цели: инициализации и уничтожения объектов. Такой тип

используется только один раз для размещения статического объекта,

чтобы вызвать конструкторы и деструкторы.



Достарыңызбен бөлісу:
1   ...   40   41   42   43   44   45   46   47   ...   124




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет