408_____________________Часть III. Современное программирование на C++

Во-первых, имейте в виду, что если вы не определите для нового класса конструктор копий, то C++ создаст его сам (табл. 17.1). Причина заключается в том, что компилятору самому может потребоваться возможность создания копий; значит, эти две функции обязаны быть определены. Во-вторых, вам может потребоваться заблокировать копирование, либо вести подсчет ссылок, или еще что-нибудь. Ерли вы не создадите эти функции, то C++ создаст для них версии по умолчанию.

Создаваемые компилятором версии обеих этих функций не всегда будут вас удовлетворять. Версии компилятора выполняют буквальное, или поразрядное, копирование. В некоторых случаях это неразумно. Не пожалейте времени на изучение ситуаций, которые могут вам встретиться при разработке программ.

Вот лишь некоторые из бесчисленного множества возможных ситуаций, в которых происходит копирование:

Х х; Х у(х); // Прямой вызов конструктора копий. Х х = у; // Выглядит как присваивание, но

// вызывает конструктор копий. Почему?

// См. нижеследующее Замечание Х х, у; х = у; // Вызов операции присваивания Х Foo(); // Возврат по значению, вызывает копирование void Foo ( X) ; // Передача по значению, создает копию

Во всех этих случаях выполняется копирование. В ходе выполняемой компилятором оптимизации могут появиться и другие варианты. Это та область, где знание действительно сила, способная помочь вам избежать утечек памяти.

Замечание

В операторе типа х х = у; не вызывается операция присваивания класса х, хотя выглядит это именно так. Причина состоит в том, что операция присваивания — это функция-член, а значит может быть вызвана только для существующих объектов, в то время как в этом фрагменте происходит создание нового объекта х.

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

Х х = у; // вызов конструктора копий

эквивалентна строке

Х х(у); // вызов конструктора копий

что совсем не то же самое, что

Х х, у;

х = у; // вызов операции присваивания