Правила программирования на С и С++. Главы 7-8
Страница 40. Присваивание самому себе должно работать


 

124. Операция operator=( ) должна возвращать ссылку на константу.

 

125. Присваивание самому себе должно работать.

 

Определение operator=( ) должно всегда иметь следующую форму:

class class_name

{

const class_name ?operator=( const class_name ?r );};

const class_name ?class_name::operator=( const class_name ?r )

{

if( this != ?r )

{

// здесь скопировать}

return *this;

}

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

Эта функция возвращает ссылку, потому что она может это сделать. То есть вы могли бы удалить ? из объявления возвращаемой величины, и все бы работало прекрасно, но вы бы получили ненужный вызов конструктора копии, вынужденный возвратом по значению. Так как у нас уже есть объект, инициализированный по типу правой части (*this), то мы просто можем его вернуть. Даже если возврат объекта вместо ссылки в действительности является ошибкой для функции operator=(), компилятор просто выполнит то, что вы ему приказали. Здесь не будет сообщения об ошибке; и на самом деле все будет работать. Код просто будет выполняться более медленно, чем нужно.

Наконец, operator=() должен возвращать ссылку на константу просто потому, что не хотите, чтобы кто-нибудь имел возможность модифицировать возвращенный объект после того, как произошло присваивание. Следующее будет недопустимым в случае возврата ссылки на константу:

(x =y) = z;Причина состоит в том, что (x=y) расценивается как возвращаемое значение функции operator=(), т.е. константная ссылка. Получателем сообщения =z является объект, только что возвращенный от x=y. Тем не менее, вы не можете послать сообщение operator=() константному объекту, потому что его объявление не имеет в конце const: // НЕ ДЕЛАЙТЕ ЭТОГО

// В ФУНКЦИИ С ИСПОЛЬЗОВАНИЕМ

// operator=().

// |

// V

const class_name ?operator=( const class_name ?r ) const;Компилятор должен выдать вам ошибку типа "не могу преобразовать ссылку на переменную в ссылку на константу", если вы попробуете (x=y)=z.

Другим спорным моментом в предыдущем коде является сравнение:

if( this != ?r )в функции operator=(). Выражение: class_name x;

// ...

x = x;

должно всегда срабатывать, и сравнение this с адресом входного правого аргумента является простым способом в этом убедиться. Имейте в виду, что многие алгоритмы полагают самоприсваивание безвредным, поэтому не делайте его особым случаем. Также имейте в виду, что самоприсваивание могло бы быть затушевано при помощи указателя как в: class_name array[10];

class_name *p = array;

// ...

*p = array[0];

 
« Предыдущая статья   Следующая статья »