55. Предпочитайте канонический вид присваивания
55. Предпочитайте канонический вид присваивания
Резюме
При реализации оператора operator= предпочитайте использовать канонический вид — невиртуальный с определенной сигнатурой.
Обсуждение
Предпочтительно объявлять копирующее присваивание для типа T с одной из следующих сигнатур (см. [Stroustrup00] и [Alexandrescu03a]):
T& operator=(const T&); // классический вид
T& operator=(T); // потенциально оптимизированный
// вид (см. рекомендацию 27)
Второй вариант имеет смысл использовать, если вам в любом случае требуется копия аргумента в теле вашего оператора, как, например, при использовании идиомы, основанной на использовании функции обмена (см. рекомендацию 56).
Избегайте делать любой оператор присваивания виртуальным (см. [Meyers96] §33 и [Sutter04] §19). Если вы полагаете, что вам требуется виртуальное поведение присваивания, обратитесь сначала к указанной литературе. Если и после этого вы стоите на своем, то лучше использовать виртуальную именованную функцию, а не оператор (например, virtual void Assign(const T&);).
He возвращайте const T&. Хотя этот тип возвращаемого значения имеет то преимущество, что защищает от странных присваиваний наподобие (a=b)=c, главным его недостатком является то, что вы не сможете поместить объекты типа T в контейнеры стандартной библиотеки; эти контейнеры требуют, чтобы оператор присваивания возвращал тип T&.
Всегда делайте копирующее присваивание безопасным в смысле исключений, причем предпочтительна строгая гарантия (см. рекомендацию 71).
Убедитесь, что ваш оператор присваивания безопасен в смысле присваивания самому себе. Избегайте написания оператора копирующего присваивания, который для корректной работы полагается на проверку присваивания самому себе; зачастую это говорит о недостаточной безопасности в смысле исключений. Если вы пишете копирующее присваивание с использованием идиомы обмена (см. рекомендацию 56), то вы автоматически обеспечиваете как строгую безопасность в смысле исключений, так и безопасность в смысле присваивания самому себе. Если присваивание самому себе часто встречается в программе из-за использования ссылочных синонимов или по каким-то иным причинам, проверка присваивания самому себе может использоваться в качестве средства оптимизации во избежание лишней работы.
Явно вызывайте все операторы присваивания базовых классов и всех данных-членов ([Meyers97] §16); обратите внимание, что идиома обмена автоматически заботится обо всех этих вещах. Возвращайте из оператора присваивания значение *this ([Meyers97] §15).
Ссылки
[Alexandrescu03a] • [Cargill92] pp. 41-42, 95 • [Cline99] §24.01-12 • [Koenig97] §4 • [Meyers96] §33 • [Meyers97] §17 • [Murray93] §2.2.1 • [Stroustrup00] §10.4.4.1, §10.4.6.3 • [Sutter00] §13, §38, §41 • [Sutter04] §19
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
R.13.4.3 Присваивания
R.13.4.3 Присваивания Функция присваивания operator=() должна быть нестатической функцией-членом. Она не наследуется (§R.12.8). Более того, если пользователь не определил для класса X функцию operator=, то используется стандартная функция operator=, которая определяется как присваивание по
14. Предпочитайте ошибки компиляции и компоновки ошибкам времени выполнения
14. Предпочитайте ошибки компиляции и компоновки ошибкам времени выполнения РезюмеНе стоит откладывать до выполнения программы выявление ошибок, которые можно обнаружить при ее сборке. Предпочтительно писать код, который использует компилятор для проверки инвариантов
28. Предпочитайте канонический вид ++ и --, и вызов префиксных операторов
28. Предпочитайте канонический вид ++ и --, и вызов префиксных операторов РезюмеОсобенность операторов инкремента и декремента состоит в том, что у них есть префиксная и постфиксная формы с немного отличающейся семантикой. Определяйте операторы operator++ и operator-- так, чтобы они
33. Предпочитайте минимальные классы монолитным
33. Предпочитайте минимальные классы монолитным РезюмеРазделяй и властвуй: небольшие классы легче писать, тестировать и использовать. Они также применимы в большем количестве ситуаций. Предпочитайте такие небольшие классы, которые воплощают простые концепции, классам,
34. Предпочитайте композицию наследованию
34. Предпочитайте композицию наследованию РезюмеИзбегайте "налога на наследство": наследование — вторая по силе после отношения дружбы взаимосвязь, которую можно выразить в С++. Сильные связи нежелательны, и их следует избегать везде, где только можно. Таким образом,
36. Предпочитайте предоставление абстрактных интерфейсов
36. Предпочитайте предоставление абстрактных интерфейсов РезюмеВы любите абстракционизм? Абстрактные интерфейсы помогают вам сосредоточиться на проблемах правильного абстрагирования, не вдаваясь в детали реализации или управления состояниями. Предпочтительно
44. Предпочитайте функции, которые не являются ни членами, ни друзьями
44. Предпочитайте функции, которые не являются ни членами, ни друзьями РезюмеТам, где это возможно, предпочтительно делать функции не членами и не друзьями классов.ОбсуждениеФункции, не являющиеся членами или друзьями классов, повышают степень инкапсуляции путем
48. В конструкторах предпочитайте инициализацию присваиванию
48. В конструкторах предпочитайте инициализацию присваиванию РезюмеВ конструкторах использование инициализации вместо присваивания для установки значений переменных-членов предохраняет от ненужной работы времени выполнения при том же объеме вводимого исходного
80. Предпочитайте push_back другим способам расширения последовательности
80. Предпочитайте push_back другим способам расширения последовательности РезюмеИспользуйте push_back везде, где это возможно. Если для вас не важна позиция вставки нового объекта, лучше всего использовать для добавления элемента в последовательность функцию push_back. Все прочие
81. Предпочитайте операции с диапазонами операциям с отдельными элементами
81. Предпочитайте операции с диапазонами операциям с отдельными элементами РезюмеПри добавлении элементов в контейнер лучше использовать операции с диапазонами (т.е. функцию insert, которая получает пару итераторов), а не последовательность вызовов функции для вставки
84. Предпочитайте вызовы алгоритмов самостоятельно разрабатываемым циклам
84. Предпочитайте вызовы алгоритмов самостоятельно разрабатываемым циклам РезюмеРазумно используйте функциональные объекты. В очень простых случаях написанные самостоятельно циклы могут оказаться более простым и эффективным решением. Тем не менее, вызов алгоритма
Правило 2: Предпочитайте const, enum и inline использованию #define
Правило 2: Предпочитайте const, enum и inline использованию #define Это правило лучше было бы назвать «Компилятор предпочтительнее препроцессора», поскольку #define зачастую вообще не относят к языку C++. В этом и заключается проблема. Рассмотрим простой пример; попробуйте написать
Правило 20: Предпочитайте передачу по ссылке на const передаче по значению
Правило 20: Предпочитайте передачу по ссылке на const передаче по значению По умолчанию в C++ объекты передаются в функции и возвращаются функциями по значению (свойство, унаследованное от C). Если не указано противное, параметры функции инициализируются копиями реальных
Правило 23: Предпочитайте функциям-членам функции, не являющиеся ни членами, ни друзьями класса
Правило 23: Предпочитайте функциям-членам функции, не являющиеся ни членами, ни друзьями класса Возьмем класс для представления Web-браузера. В числе прочих такой класс может предлагать функции, который очищают кэш загруженных элементов, очищают историю посещенных URL и