Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ
Шрифт:
Также интересно, что оператор присваивания правоассоциативен, поэтому приведенный выше пример присваивания интерпретируется следующим образом:
Здесь переменной z присваивается значение 15, затем результат присваивания (новое значение z) присваивается переменной y, после чего результат (новое значение y) присваивается переменной x.
Достигается это
Это соглашение касается всех операторов присваивания, а не только стандартной формы, показанной выше. Следовательно:
Это всего лишь соглашение. Если программа его не придерживается, она тем не менее скомпилируется. Однако ему следуют все встроенные типы, как и все типы (см. правило 54) стандартной библиотеки (то есть string, vector, complex, tr1::shared_ptr и т. д.). Если у вас нет веской причины нарушать соглашение, не делайте этого.
• Пишите операторы присваивания так, чтобы они возвращали ссылку на *this.
Правило 11: В operator= осуществляйте проверку на присваивание самому себе
Присваивание самому себе возникает примерно в такой ситуации:
Код выглядит достаточно нелепо, однако он совершенно корректен, и в том, что программисты на такое способны, вы можете не сомневаться ни секунды.
Кроме того, присваивание самому себе не всегда так легко узнаваемо. Например:
это присваивание себе, если i
тоже становится присваиванием самому себе, если окажется, что px и py указывают на одно и то же.
Эти менее очевидные случаи присваивания себе являются результатом совмещения имен (aliasing), когда для ссылки на объект существует более одного способа. Вообще, программа, которая оперирует ссылками или указателями на различные объекты одного и того же типа, должна считаться с тем, что эти объекты могут совпадать. Необязательно даже, чтобы два объекта имели одинаковый тип, ведь если они принадлежат к одной иерархии классов, то ссылка или указатель на базовый класс может в действительно относиться к объекту производного класса:
Если вы следуете правилам 13 и 14, то всегда пользуетесь объектами для управления ресурсами; следите за тем, чтобы управляющие объекты правильно вели себя при копировании. В таком случае операторы присваивания должны быть безопасны относительно присваивания самому себе. Если вы пытаетесь управлять ресурсами самостоятельно (а как же иначе, если вы пишете класс для управления ресурсами), то можете попасть в ловушку, нечаянно освободив ресурс до его использования. Например, предположим, что вы создали класс, который содержит указатель на динамически распределенный объект класса Bitmap:
Ниже приведена реализация оператора присваивания operator=, которая выглядит совершенно нормально, но становится опасной в случае выполнения присваивания самому себе (она также небезопасна с точки зрения исключений, но сейчас не об этом).
Проблема состоит в том, что внутри operator= *this (чему присваивается значение) и rhs (что присваивается) могут оказаться одним и тем же объектом. Если это случится, то delete уничтожит не только Bitmap, принадлежащий текущему объекту, но и Bitmap, принадлежащий объекту в правой части. По завершении работы этой функции Widget, который не должен был бы измениться в процессе присваивания самому себе, содержит указатель на удаленный объект!
Сердце Дракона. Том 20. Часть 1
20. Сердце дракона
Фантастика:
фэнтези
боевая фантастика
городское фэнтези
рейтинг книги
Холодный ветер перемен
7. Девяностые
Фантастика:
попаданцы
альтернативная история
рейтинг книги
Последнее желание
1. Ведьмак
Фантастика:
фэнтези
рейтинг книги
Отмороженный 7.0
7. Отмороженный
Фантастика:
рпг
аниме
рейтинг книги
Наследник
1. Рюрикова кровь
Фантастика:
научная фантастика
попаданцы
альтернативная история
рейтинг книги
