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

В случае, если у класса имеется конструктор, он вызывается всегда при создании объекта этого класса. В случае, если у класса имеется деструктор, он вызывается всегда, в то время, когда уничтожается объект этого класса. Объект может создаваться как: [1] непроизвольный, что создается любой раз, в то время, когда его описание видится при исполнении программы, и уничтожается по выходе из блока, в котором он обрисован; [2] статический, что создается один раз при запуске программы и уничтожается при ее завершении; [3] объект в свободной памяти, что создается операцией new и уничтожается операцией delete; [4] объект-член, что создается в ходе создания другого класса либо при создании массива, элементом которого он есть. Также объект может создаваться, в случае, если в выражении очевидно употребляется его конструктор ($$7.3) либо как временный объект ($$R.12.2). И в том и другом случае таковой объект не имеет имени. В следующих подразделах предполагается, что объекты относятся к классу с деструктором и конструктором. Как пример употребляется класс table из $$5.3.1.

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

Конструктор локальной переменной вызывается любой раз, в то время, когда при исполнении программы видится ее описание. Деструктор локальной переменной вызывается всегда по выходе из блока, где она была обрисована. Деструкторы для локальных переменных вызываются в порядке, обратном вызову конструкторов при их создании: void f(int i) { table aa; table bb; if (i0) { 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).

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

Разглядим таковой пример: 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). Время от времени при разработке библиотеки не редкость нужно либо легко комфортно создать тип с деструктором и конструктором лишь для одной уничтожения: и цели инициализации объектов. Таковой тип употребляется лишь один раз для размещения статического объекта, дабы позвать деструкторы и конструкторы.

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

Разглядим пример: main() { table* p = new table(100); table* q = new table(200); delete p; delete p; // возможно, приведёт к ошибке при исполнении } Конструктор table::table() будет вызываться два раза, как и деструктор table::~table(). Но это ничего не означает, т.к. в С++ не гарантируется, что деструктор будет вызываться лишь для объекта, созданного операцией new. В этом примере q не уничтожается по большому счету, но p уничтожается два раза! В зависимости от типа p и q программист может вычислять либо не считать это неточностью. То, что объект не удаляется, в большинстве случаев бывает не неточностью, а просто утратой памяти. Одновременно с этим повторное удаление p — важная неточность. Повторное использование delete к тому же самому указателю может привести к нескончаемому циклу в подпрограмме, управляющей свободной памятью. Но в языке итог повторного удаления не выяснен, и он зависит от реализации. Пользователь может выяснить собственную реализацию операций new и delete (см. $$3.2.6 и $$6.7). Помимо этого, возможно установить сотрудничество конструктора либо деструктора с операциями new и delete (см. $$5.5.6 и $$6.7.2). Размещение массивов в свободной памяти обсуждается в $$5.5.5.

ООП для начинающих PHP. Конструкторы и деструкторы. Магические методы.


Интересные записи:

Понравилась статья? Поделиться с друзьями: