Освобождение р-памяти.
Как подтверждают результаты выполнения этой программы, при создании объекта
Следует иметь в виду, что конструктор копии вызывается только в случае выполнения инициализации. Например, следующая последовательность инструкций не вызовет конструктор копии, определенный в предыдущей программе:
myclass а(2), b(3);
// ...
b = а;
Здесь инструкция
Конструктор копии также вызывается при создании временного объекта, который является результатом возвращения функцией объекта. Рассмотрим следующую короткую программу.
/* Конструктор копии вызывается в результате создания временного объекта в качестве значения, возвращаемого функцией.
*/
#include
using namespace std;
class myclass {
public:
myclass() { cout << "Обычный конструктор.\n"; }
myclass(const myclass &obj) {cout << "Конструктор копии.\n"; }
};
myclass f()
{
myclass ob; // Вызывается обычный конструктор.
return ob; // Неявно вызывается конструктор копии.
}
int main()
{
myclass a; // Вызывается обычный конструктор.
а = f(); // Вызывается конструктор копии.
return 0;
}
Эта программа генерирует такие результаты.
Обычный конструктор.
Обычный конструктор.
Конструктор копии.
Здесь обычный конструктор вызывается дважды: первый раз при создании объекта
Хотя "скрытые" вызовы конструкторов копии могут отдавать мистикой, нельзя отрицать тот факт, что практически каждый класс в профессионально написанных программах содержит явно определенный конструктор копии, без которого не избежать побочных эффектов, возникающих в результате создания по умолчанию побитовых копий объекта.
Как уже неоднократно упоминалось в этой книге, C++ — очень мощный язык. Он имеет множество средств, которые наделяют его широкими возможностями, но при этом его можно назвать сложным языком. Конструкторы копии представляют собой механизм, на который ссылаются многие программисты как на основной пример сложности языка, поскольку это средство не воспринимается на интуитивном уровне. Начинающие программисты часто не понимают, почему так важен конструктор копии. Для многих не сразу становится очевидным ответ на вопрос: когда нужен конструктор копии, а когда — нет. Эта ситуация часто выражается в такой форме:
Такие языки, как Java и С#, не имеют конструкторов копии, поскольку ни в одном из них не создаются побитовые копии объектов. Дело в том, что как Java, так и C# динамически выделяют память для всех объектов, а программист оперирует этими объектами исключительно через ссылки. Поэтому при передаче объектов в качестве параметров функции или при возврате их из функций в копиях объектов нет никакой необходимости.
Тот факт, что ни Java, ни C# не нуждаются в конструкторах копии, делает эти языки проще, но за простоту тоже нужно платить. Работа с объектами исключительно посредством ссылок (а не напрямую, как в C++) налагает ограничения на тип операций, которые может выполнять программист. Более того, такое использование объектных ссылок в Java и C# не позволяет точно определить, когда объект будет разрушен. В C++ же объект всегда разрушается при выходе из области видимости.
Язык C++ предоставляет программисту полный контроль над ситуациями, складывающимися в программе, поэтому он несколько сложнее, чем Java и С#. Это — цена, которую мы платим за мощность программирования.
Ключевое слово this
—