Читаем Стандарты программирования на С++ полностью

public:

 FlagNth(size_t n) : current_(0), n_(n) { }

 // Возвращаем значение true только при третьем вызове

 template

 bool operator()(const T&)     // Плохо: неконстантная

  { return ++current_ == n_; } // функция

private:

 size_t current_, n_;

};

// ... позже ...

v.erase(remove_if(v.begin(), v.end(), FlagNth(3)));

Увы, нет никакой гарантии, что будет удален именно третий элемент В большинстве реальных реализаций STL приведенный код наряду с третьим удалит и шестой элемент. Почему? Потому что remove_if обычно реализуется с использованием find_if и remove_copy_if, и копия предиката передается каждой из этих функций.

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

Корректный способ удаления третьего элемента — выполнить итерации для его поиска и вызвать функцию erase.

Ссылки

[Austern99] §4.2.2 • [Josuttis99] §5.8.2, §8.1.4 • [Meyers01] §39 • [Stroustrup00] §10.2.6 • [Sutter02] §2-3

<p>88. В качестве аргументов алгоритмов и компараторов лучше использовать функциональные объекты, а не функции</p>Резюме

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

Обсуждение

Во-первых, функциональные объекты легко сделать адаптируемыми (и такими их и следует делать — см. рекомендацию 89). Даже если у вас есть готовая функция, иногда для ее использования требуется "обертка" из ptr_fun или mem_fun. Например, такая обертка требуется при построении более сложных выражений с использованием связывателей (см. также рекомендацию 84):

inline bool isHeavy(const Thing&) { /* ... */ }

find_if(v.begin(), v.end(), not1(IsHeavy)); // Ошибка

Обойти эту ошибку обычно можно путем применения ptr_fun (или, в случае функции-члена, mem_fun или mem_fun_ref), что, к сожалению, не работает в данном конкретном случае:

inline bool IsHeavy(const Thing&) { /* ... */ }

find_if(v.begin(), v.end(),

 not1(ptr_fun(IsHeavy))); // Героическая попытка...

Беда в том, что этот способ не будет работать, даже если вы явно укажете аргументы шаблона ptr_fun. Коротко говоря, проблема в том, что ptr_fun точно выводит типы аргументов и возвращаемый тип (в частности, тип параметра будет выведен как const Thing&) и создает внутренний механизм, который, в свою очередь, пытается добавить другой &, а ссылка на ссылку в настоящее время в C++ не разрешена. Имеются способы исправлений языка и/или библиотека для решения данной проблемы (например, позволяя ссылке на ссылку свернуться в обычную ссылку; см. также рекомендацию 89), но на сегодняшний день проблема остается нерешенной.

Прибегать ко всем этим ухищрениям совершенно излишне, если у вас имеется корректно написанный функциональный объект (см. рекомендацию 89), который можно использовать без какого-либо специального синтаксиса:

struct IsHeavy : unary_function {

 bool operator()(const Thing&) const { /* ... */ }

};

find_if(v.begin(), v.end(), not1(IsHeavy())) ; // OK

Еще более важно то, что для определения сравнения в ассоциативных контейнерах вам нужен именно функциональный объект, а не функция. Это связано с тем, что нельзя инстанцировать шаблон с функцией в качестве параметра:

bool CompareThings(const Thing&, const Thing&);

set s; // Ошибка

Вместо этого следует написать:

struct CompareThings

 : public binary_function {

 bool operator()( const Thing&, const Thing& ) const;

};

set s; //OK

Наконец, имеется еще одно преимущество функциональных объектов — эффективность. Рассмотрим следующий знакомый алгоритм:

template

Перейти на страницу:

Все книги серии C++ In-Depth

Стандарты программирования на С++
Стандарты программирования на С++

Эта книга поможет новичку стать профессионалом, так как в ней представлен сконцентрированный лучший опыт программистов на С++, обобщенный двумя экспертами мирового класса.Начинающий программист найдет в ней простые и понятные рекомендации для ежедневного использования, подкрепленные примерами их конкретного применения на практике.Опытные программисты найдут в ней советы и новые рекомендации, которые можно сразу же принять на вооружение. Программисты-профессионалы могут использовать эту книгу как основу для разработки собственных стандартов кодирования, как для себя лично, так и для группы, которой они руководят.Конечно, книга рассчитана в первую очередь на профессиональных программистов с глубокими знаниями языка, однако она будет полезна любому, кто захочет углубить свои знания в данной области.

Андрей Александреску , Герб Саттер

Программирование, программы, базы данных

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных