Статья: Классы: копирование и присваивание

if(this == &rhs) return *this; // проверка на присваивание себе

else { X=rhs.X; Y=rhs.Y; } //то, что делает оператор полезного

return *this; // возврат ссылки на объект

}

Сейчас мы попробуем в ней разобраться, благо для всех операций присваивания проверка на присваивание себе со-вершенно одинакова. Оператор if(this == &rhs) проверяет, не совпадает ли аргумент с самим объектом. Указатель this со-держит адрес вызывающего объекта, &rhs читается как "адрес rhs".

Таким образом, сравниваются два адреса. Если они эквивалентны (==), то это один и тот же объект. В этом случае, в полном соответствии с требованием воз-врата ссылки на объект, просто возвращаем *this (заметьте, что в конце функции делается то же самое) и выходим из функции.

Вспомните, что this - это указатель. Значение указателя - это адрес. Чтобы получить значение указателя, его следует разыменовывать. Разыменование указателя выглядит так: *ptr. Указатель this разыменовывается точно так же: *this.

Помещая эти две строки в начале и в конце тела операции присваивания, мы уменьшаем вероятность возникновения утечек памяти из-за этой опера-ции. Если вы запомнили приведенный здесь синтаксис копирования и при-сваивания и, определяя новый класс, сразу будете определять и их тоже, то это уже полдела.

Зачем C++ требует определения этих функций-членов?

Язык C++ не слишком сильно ограничивает свободу программистов в методах разработки программного обеспечения. В частности, он не навязывает вам способы копирования и присваивания. Количество и разнообразие ситуаций, в которых происходит копирование объектов, удивительно велико. Для очень простых объектов, состоящих из одного-двух элементов, затраты на копирование незначительны, но для более сложных, таких как графический интерфейс пользователя или комплексные типы данных, оперирующие с динамической памятью, издержки на копирование существенно возрастают.

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

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

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

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

POINT х;

POINT у(х); // Прямой вызов конструктора копий.

POINT х = у; // Выглядит как присваивание, но на самом деле

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

POINT a, b;

a = b; // Вызов операции присваивания

POINT Foo(); // Возврат по значению, вызывает копирование

void Foo(POINT); // Передача по значению, создает копию

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

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

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

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

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

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

БИКЮ , что совсем не то же самое, что

К-во Просмотров: 212
Бесплатно скачать Статья: Классы: копирование и присваивание