Это проблематичное решение, поскольку если вы помещаете эту функцию в пространство имен, в котором находится
Widget
, то многие реализации просто не в состоянии найти ее, но при этом стандарт запрещает располагать данную функцию в пространстве имен
std
. Эта проблема никогда бы не возникла, если бы стандарт либо указывал, что перегрузки надо искать и в пространстве имен типа шаблона, либо позволял помещать перегружаемые функции в пространство имен
std
, или (возвращаясь к основному вопросу данной рекомендации) прямо указывал, что
swap
должна реализовываться с использованием шаблона класса, который может быть частично специализирован.
Используйте для реализации функциональности наиболее обобщенные и абстрактные средства.
Обсуждение
Когда вы пишете тот или иной код, используйте наиболее абстрактные средства, позволяющие решить поставленную задачу. Всегда думайте над тем, какие операции накладывают меньшее количество требований к интерфейсам, с которыми они работают. Такая привычка сделает ваш код более обобщенным, а следовательно, в большей степени повторно используемым и более приспособленным ко внесению изменений в его окружение.
И напротив, код, неоправданно привязанный к деталям, оказывается чрезмерно "жестким" и неспособным к повторному использованию.
• Используйте для сравнения итераторов
!=
вместо
<
. Оператор
!=
более общий и применим к большему классу объектов; оператор
<
требует упорядочения и может быть реализован только итераторами произвольного
доступа. При использовании оператора
!=
ваш код проще переносится для работы с другими типами итераторов, такими как одно- и двунаправленные итераторы.
• Лучше использовать итераторы, а не индексы. Многие контейнеры не поддерживают индексный доступ; например, контейнер
list
не в состоянии эффективно реализовать его. Однако все контейнеры поддерживают итераторы. Таким образом, итераторы обеспечивают большую обобщенность кода, и при необходимости они могут использоваться совместно с индексным доступом.
• Используйте
empty
вместо
size==0
. "Пуст/не пуст" — более примитивная концепция, чем "точный размер". Например, вы можете не знать размер потока, но всегда можете сказать о том, пуст он или нет; то же самое справедливо и для входных итераторов. Некоторые контейнеры, такие как
list
, реализуют
empty
более эффективно, чем
size
.
• Используйте наивысший класс иерархии, предоставляющий необходимую вам функциональность. При программировании с использованием динамических полиморфных классов не следует делать код зависимым от ненужных вам деталей и привязываться к определенным производным классам.
• Будьте корректны при использовании
const
(см. рекомендацию 15). Передача параметров
const&
накладывает меньше ограничений на вызывающий код, поскольку
const&
охватывает как константные, так и неконстантные объекты.
Исключения
В некоторых случаях применение индексов вместо итераторов позволяет компилятору лучше оптимизировать код. Однако перед тем как решиться на такой шаг, убедитесь, что вы действительно в нем нуждаетесь и что ваш компилятор действительно при этом лучше оптимизирует ваш код (см. рекомендацию 8).
Имеется три способа написать программу без ошибок; но работает только третий способ.
— Алан Перлис (Alan Perlis)
Вопрос не в том, будем ли мы делать программные ошибки. Вопрос в том, будем ли мы что-либо предпринимать, чтобы позволить компилятору и другим используемым инструментам их обнаружить.
В этом разделе документированы добытые трудом множества программистов знания и наилучшие практические подходы, некоторые из которых стоили многих лет работы. Следуйте приведенным правилам и рекомендациям. Когда мы пишем сложную, надежную и безопасную программу — нам требуется вся помощь, которую мы только в состоянии получить.