namespace N {

 template<typename T> class Widget { /* ... */ };

}

то специализация std::swap попросту невозможна, так как частичной специализации шаблона функции не существует. Лучшее, что вы можете сделать, — это добавить перегрузку функции

namespace ??? {

 template<typename T> void swap(Widget<T>&, Widget<T>&);

}

Это проблематичное решение, поскольку если вы помещаете эту функцию в пространство имен, в котором находится Widget, то многие реализации просто не в состоянии найти ее, но при этом стандарт запрещает располагать данную функцию в пространстве имен std. Эта проблема никогда бы не возникла, если бы стандарт либо указывал, что перегрузки надо искать и в пространстве имен типа шаблона, либо позволял помещать перегружаемые функции в пространство имен std, или (возвращаясь к основному вопросу данной рекомендации) прямо указывал, что swap должна реализовываться с использованием шаблона класса, который может быть частично специализирован.

Ссылки

[Austern99] §A.1.4 • [Sutter04] §7 • [Vandevoorde03] §12

67. Пишите максимально обобщенный код

Резюме

Используйте для реализации функциональности наиболее обобщенные и абстрактные средства.

Обсуждение

Когда вы пишете тот или иной код, используйте наиболее абстрактные средства, позволяющие решить поставленную задачу. Всегда думайте над тем, какие операции накладывают меньшее количество требований к интерфейсам, с которыми они работают. Такая привычка сделает ваш код более обобщенным, а следовательно, в большей степени повторно используемым и более приспособленным ко внесению изменений в его окружение.

И напротив, код, неоправданно привязанный к деталям, оказывается чрезмерно 'жестким' и неспособным к повторному использованию.

• Используйте для сравнения итераторов ! = вместо <. Оператор ! = более общий и применим к большему классу объектов; оператор < требует упорядочения и может быть реализован только итераторами произвольного доступа. При использовании оператора != ваш код проще переносится для работы с другими типами итераторов, такими как одно- и двунаправленные итераторы.

• Лучше использовать итераторы, а не индексы. Многие контейнеры не поддерживают индексный доступ; например, контейнер list не в состоянии эффективно реализовать его. Однако все контейнеры поддерживают итераторы. Таким образом, итераторы обеспечивают большую обобщенность кода, и при необходимости они могут использоваться совместно с индексным доступом.

• Используйте empty() вместо size() ==0. 'Пуст/не пуст' — более примитивная концепция, чем 'точный размер'. Например, вы можете не знать размер потока, но всегда можете сказать о том, пуст он или нет; то же самое справедливо и для входных итераторов. Некоторые контейнеры, такие как list, реализуют empty более эффективно, чем size.

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

• Будьте корректны при использовании const (см. рекомендацию 15). Передача параметров const& накладывает меньше ограничений на вызывающий код, поскольку const& охватывает как константные, так и неконстантные объекты.

Исключения

В некоторых случаях применение индексов вместо итераторов позволяет компилятору лучше оптимизировать код. Однако перед тем как решиться на такой шаг, убедитесь, что вы действительно в нем нуждаетесь и что ваш компилятор действительно при этом лучше оптимизирует ваш код (см. рекомендацию 8).

Ссылки

[Koenig97] §12.7, §17-18 • [Meyers01] §4 • [Stroustrup00] §13, §17.1.1 • [Sutter04] §1, §5, §34

Обработка ошибок и исключения

Обработка ошибок — сложная задача, при решении которой программисту требуется вся помощь, которая только может быть предоставлена.

— Бьярн Страуструп (Bjarne Stroustrup), [Stroustrup94] §16.2

Имеется три способа написать программу без ошибок; но работает только третий способ.

— Алан Перлис (Alan Perlis)

Вопрос не в том, будем ли мы делать программные ошибки. Вопрос в том, будем ли мы что-либо предпринимать, чтобы позволить компилятору и другим используемым инструментам их обнаружить.

В этом разделе документированы добытые трудом множества программистов знания и наилучшие практические подходы, некоторые из которых стоили многих лет работы. Следуйте приведенным правилам и рекомендациям. Когда мы пишем сложную, надежную и безопасную программу — нам требуется вся помощь, которую мы только в состоянии получить.

В этом разделе мы считаем наиболее значимой рекомендацию 69 — 'Определите разумную стратегию обработки ошибок и строго ей следуйте'.

68. Широко применяйте assert для документирования внутренних допущений и инвариантов

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату