Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 63
Текст из файла (страница 63)
Размер конкретного типа известен во время компиляции, поэтому объекты могут быть помещены в стек (то есть не используется выделение свободной памяти). Способ хранения каждого объекта известен во время компиляции, поэтому встраивание операций достигается тривиальным образом. Аналогично, совместимость с дру- ~ ими языкамн, типа С и Гогггап, достигается без специальных усилий.
Хороший набор конкретных типов может создать фундамент приложения. Отсутствие подходящих «маленьких эффективных типов» в приложении может привести к увеличению времени выполнения и к неэффективному расходованию памяти в результате использования чрезмерно обобщенных и больших классов. С другой стороны, отсутствие конкретных типов может привести к запутанным программам и потерям времени, когда каждый программист пишет код для непосредственного манипулирования «простыми и часто пспользуеьчыми» структурами данных.
10.4. Объекты Объекты могут создаваться нссколькимп способами. Некоторые обьекты являюгся локальными переменными, другие -- глобальными, третьи — членами классов и т. д. В данном разделе обсуждаются эти альтернативы, правила работы с объектами, конструкторы, используемые для инициализации объектов, и деструкторы, применяемые для «очистки> объектов перед тем, как онп станут недоступнымп. 10.4.1. Деструкторы Конструкторы инициализируют объект. Другими словамп, они создают среду, в ко~арой работают функции-члены. Иногда создание такой среды подразумевает захват каких-то ресурсов — таких как файл, блокировка пли пал~ять, которые должны быль освобождены после их использования 19 11 тй7). В результате, некоторым классам требуется функция, которая будет гарантированно вызвана при уничтожении объекта, аналогично конструктору, который гарантированно вызывается прп создании объекта.
Как вы догадываетесь, такие функции называются д'еггпрук>порами. Они, как правило, очищают память и освобождают ресурсы. Деструкторы вызываются неявно, когда автома~ическая переменная выходит из области видимости, удаляется объект, хранящийся в свободной памяти и т. д. '1 олько в очень необычных ситуациях пользователю требуется явно вызывать деструктор Я 10.4.11). Наиболее часто деструктор используется для освобождении памяти, выделенной конструктором. Рассмотрим простую таблицу элементов типа Агапте. Конструктор класса ТаЫе лолжен выделить память для хранения э.лементов.
Пос.ле того как таблица уничтожена каким-либо способом, мы должны быть уверены, что эта память будет 290 Глава 1О. Классы освобождена для дальнейшего использована. Мы можем добиться этого, реализовав специальную функцию, дополняющую конструктор: с!аз я Лате ( сопя! сйаг* я; с1аяя ТаЫе( Хите" р, нее !яа; риЫ1с: ТаЫе (я!ее !я =!о! (р =пешХите(ее = я),) !!конструктор -Та Ые () ( г!е1е!е() р; ) О' деструктор Мате" !ооиир (сопя! спас'); Ьоо! тяегт (Мотет, В записи деструктора -ТаЫе () используется сил~вол дополнения — !гильда) в качестве напоминания о его связи с конструктором ТаЫе ().
Комплиментарные пары конструктор/деструктор являются типичным механизмом в С+к- для выражения понятия объекта переменного размера. Контейнеры стандартной библиотеки, такие как тар, использую~ различные варианты этой техники для выделения памяти под свои элементы, так что последующее обсуякдение иллюстрирует технику, с которой вы имеете дело каждый раз, когда используете стандартньш контейнер !включая стандартныи класс я1г!пй). Обсуждение применимо и к типам без деструкторов. Такие типы можно рассматривать как типы, деструкторы которых ничего не делают.
10.4.2. Конструкторы по умолчанию Лналогичным образом моякно полагать, что многие типы имеют конструкторы по умолчанию. Конструктор по умолчаншо является конструктором, вызываемым без аргумента. В примере, приведенном выше, 15 является аргументом по умолчанию, поэтому ТаЫе: ТаЫе (явке !) является конструктором по умолчанию. Если пользователь объявил конструктор по умолчанию, он и будет задействован.
В противном случае !и если пользователь не обьявил другие конструкторы) компилятор попытается при необходимости сгенерировать конструктор по умолчанию. Конструктор по умолчанию, сгенерированный компилятором, неявно вызывает конструкторы по умолчанию для членов класса и конструкторы базовых классов Я 12.2.2). Например: Игис! ТаЫея ( !л11; !и! Ы(10); ТаЫе 11; ТаЫе И(10); ); ТаЫея !1; 291 10.4. Объекты В этом примере переменная 11 будет проинициалпзирована сгенерированным конструктором по умолчанию, который вызовет ТаЫе 115~ для 11.11 и каждого элемента 1йий С другой стороны, йу и элементы Гби1 не проинициализнрованы, потому что их тип не является класс ом.
Причина различной обработки классов и встроенных типов заключается в требовании совместимости с С и в боязни вызвать дополнительные затраты времени на этапе выполнения. Так как константы и ссылки должны быть проинициалпзированы (9 5.5, 9 5А), класс, содержащий члены, являющиеся константами или ссылками, не может быть сконструирован по умолчанию, если только программист це предоставил явно конструктор (9 10.4.6.1). Например: зГгисГХ( сапз1 1пт а, сап зГ 1пЖ г, О о~иибка: пел~ конгтдрюпара па умолкаю~а алп Х Хх, Конструкторы по умолчанию можно вызывать явно (9 10.4.10). Встроенные типы также имеют конструкторы по умолчанию (9 6.2.8).
10.4.3. Конструирование и уничтожение Рассмотрим различные способы создания и последуюп1его уничтожения объектов. Объект может быть создан в качестве; 9 10А.4 Икгенованного автоматического объекта, создаваемого каждый раз, когда встречается его объявление во время выполнения программы н уничтожаемого при каждом выходе из блока, в котором он объявлен. б 10А.5 Объекта в свободной памяти, создаваемого при помощи оператора пеш и уничтожаемого оператором Пе1е1е. 9 10А.6 Нестатического члена-объекта, который создается и уничтожается тогда, когда создае гся н уничтожается содержащий его объект. 9 10А.7 Элемента массива, который создается и уничтожается тогда, когда создастся и уничтожается массив, элементол~ которого он является.
'ф 10.4.8 Локального статического объекта, который создается, когда его объявление встречается первый раз при вьпюлпении программы и уничтожается один раз, при завершении программы. 9 10.4.9 Глобального объекта, объекта в пространстве пл~ен или статического объекта класса, которые создаются один раз кво время запуска программыыи унпчтол аются один раз, при ее завершении. 9 10.4.10 Временного объекта, который создается как часть вычисления выражения и уничтожается по завершении вычисления всего выражения. ф 10.4.11 Объекта, помещенного в память, выделенную функцией пользователя, учитывающей аргументы, которые передаются ей операцией выделения памяти.
й 10А,! 2 Члена объединения ип1оп, который не может иметь ни конструктора, ни деструктора. Список отсортнрован (приблизительно) в порядке важности. В следующих подразделах объясняются эти способы создання объектов и пх использования. Глава 10. Классы 10.4.4. Локальные переменные Та61е аа; ТаЫе ЬЬ, (Т (1>Р) ( ТаЫе се; 0 ) ТаЫе сЫ; 1! ) В этом примере при каждом вызове Я переменные аа, ЬЬ и с)с) создаются именно в таком сюрядке н уничтожаются каждый раз при выходе из ! () в порядке сгс1, ЬЬ, аа.
Если во время вызова выполнится условие 1>О, переменная се будет создана после ЬЬ и уничтожена до создания сЫ, 10.4.4.1. Копирование объектов Если 11 и 12 являкэтся объектами класса ТаЫе, выражение 12=11 по умолчанию означает почленное копирование И в 12 Я 10.2.5). При наличии у объекта членов, являющихся указателями, такая интерпретация присваивания может вызвать неожиданный (и обычно нежелательный) эффект. Почленпое копирование обычно является неправильным при копировании объектов, имеющих ресурсы, управляемые парой конструктор/деструктор. Например; оои16 () ТаЫе 11; ТаЫе 12 = 11, ТаЫе 13; !!копирующая иниииплиэияил —,проблема (! копиррю~члее приееоиионие — проблема 12=12, В этом примере конструктор ТаЫе по умолчанию будет вызван дважды — по одному разу для 1! и 13. Он не вызовется для 12, потому что эта переменная проинпциалнзирована при помокни копирования. Однако деструктор ТаЫе вызывался трн раза: для 11, 12 и И По умолчанию копирование интерпретируется как почленное копирование, поэтому 11, 12 и 12 к концу Ь () будут содержать указатели на массив имен, выделенный в свободной памяти при созланпп И.
Не осталось указателя па массив имен, выделенный при создании 1о, потому что он перезаписан присваиванием 1о"=12. В результате при отсутствии автоматисеской сборки мусора (() 10А.5), эта память будет навсегда потеряна для программы. С другой стороны, массив, созданный для 11, будет и в 11, и в 12, н в 13, поэтому он будет трижды удаляться.
Результат непредсказуем и, вероятно, приведет к катастрофе. Конструктор локальной переменной вызывается каждый раз, когда управление передается инструкции, содержащей объявление этой локальной переменной. Деструктор локальной переменной выполняется каждый раз, когда происходит выход из блока, содержащего объявление локальной переменной. Деструкторы локальных объектов выполняются в порядке, противоположном выполнению их конструкторов. Например: оо)с(,1(1п1 0 293 10.4. Объекты Можно избежать подобных аномалий, определив, гго понимать пол копированием Тайе: с1аяя ТаЫе ( О".
ТаЫе (сопя! Таб!е&); ТаЫе& орега1ог= (сопя1 Таб!е&) ); уу коппругтппп конструктор О конпруклиее присваивоние Программист может определить любой подходящий смысл этих операций копирования, но традиционным реп)ением является поэлемент ное копирование хранимых элементов (нлн по крайней. мере, создание у пользователя иллюзии, что такое копирование произведено;см. 9 11.12).Например: ТаЫе Таб!е (сопя! Таб(е& 1) О конпрутауп! конструк~пор ( р = пего!»ате(ее=1.яг); !Ог (сп11=0,1<ее; !«»(р(1) ='1р(!), ) ТаЫе& ТаЫе-орега1ог= (сопя! Таб!е& 1) /! присвсшвание ( ~ уберечься от присваивания со,поиу себе: 1=1 (Т (Ийя '= &1) ( // чтоб» с!е!е1е() р; р = лет хате(ее=1.яе) Твг (!п1 1=0; !<Яг, 1»«(РЯ =1 Р(с]; ге1игп "16!я, ) 10.4.5. Свободная память Для объекта, создаваемого в свободной памяти, вызываез ся конструктор класса, ука- занного в операторе лето.