Правила программирования на Си и Си++



         

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];




Содержание  Назад  Вперед