2009-04-09 2 views
6

Я использую много STL код с std::for_each, bind и т. Д., Но я заметил, что иногда использование STL - это не очень хорошая идея.Сколько из STL слишком много?

Например, если у вас есть std::vector и хотите сделать одно действие для каждого элемента вектора, ваша первая идея состоит в том, чтобы использовать эту функцию:

std::for_each(vec.begin(), vec.end(), Foo()) 

и это элегантный и хорошо, на некоторое время. Но затем появляется первый набор отчетов об ошибках, и вам нужно изменить код. Теперь вы должны добавить параметр для вызова Foo(), так что теперь она становится:

std::for_each(vec.begin(), vec.end(), std::bind2nd(Foo(), X)) 

но это лишь временное решение. Теперь проект созревает, и вы понимаете бизнес-логику намного лучше, и вы хотите добавить новые изменения в код. Именно в этот момент вы понимаете, что вам следует использовать старый товар:

for(std::vector::iterator it = vec.begin(); it != vec.end(); ++it) 

Это случается только для меня? Вы распознаете этот тип шаблона в своем коде? Имеете ли вы аналогичные анти-шаблоны, используя STL?

+1

BTW, если в вашем втором примере «X» одинаково для всех элементов. Просто передайте его конструктору Foo и сохраните его в функторе вместо привязки. Гораздо проще. –

+0

На самом деле вы не используете ни один из STL, поэтому вы в безопасности :) –

+0

Просто мнение, но «слишком много» - это когда вы используете функции, которые вам не нужны исключительно ради их использования. Если это полезно, используйте его. Если вы беспокоитесь о слишком длинных именах, вы всегда можете использовать псевдоним typedef или псевдоним пространства имен, чтобы сократить их (например, 'typedef std :: vector :: iterator VecIter;'). Вещь со стандартной библиотекой - это, как правило, самый чистый общий способ сделать что-то на данном компиляторе просто потому, что либо создатели компилятора, либо люди, которые знают это лучше всего (если не создатели), напишут его реализацию. Не бойтесь использовать его, когда это полезно. –

ответ

10

Использование boost::bind с std :: for_each решает эту проблему в чистом виде. Или вы можете использовать BOOST_FOREACH.

Пример станд :: for_each:

std::for_each(v.begin(), v.end(), boost::bind(&C::f, _1, param)); 

Пример BOOST_FOREACH:

std::list<int> list_int(/*...*/); 
BOOST_FOREACH(int i, list_int) 
{ 
    // do something with i 
} 
+0

... пока не получите 10 параметров, то есть! :) – Kylotan

+1

, после чего вы группируете их вместе внутри структуры :) –

+2

Нет, в этот момент вы пересматриваете архитектуру, в которой требуется функция, чтобы иметь 10 параметров;) –

3

Похожие на ваш вопрос, я часто замечаю, что "функтор" шаблон/идиома в C++ на самом деле довольно громоздкий. Вот почему я с нетерпением жду Lambda Functions в C++ 0X. Некоторые из них возможны с boost :: lambda.

+0

OMG, синтаксис ... 0X имеет еще 8 месяцев до его окончания плюс 3+ года, пока крупные компиляторы не догонят. Это будет долго. –

+1

@ Антон: Это уже в g ++ и Visual Studio 10 (теперь доступно RC) –

10

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

for() 
{ 
    // do 
    // some 
    // stuff 
} 

Тогда как операция вам нужно выполнить становится более сложным, вы понимаете, что тянет его в отдельную функцию имеет смысл, так что вы в конечном итоге с

for() 
    do_alot_more_stuff(); 

А затем изменить его, чтобы быть, как ваш оригинальный метод имеет смысл, чтобы сконденсировать его дальше вниз:

std::for_each(begin, end, do_alot_more_stuff); 

В конце концов, как трудно действительно изменить for_each на цикл for, или наоборот? Не бить себя крошечными деталями!

5

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

+0

Точно. Что случилось с изменением кода? –

0

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

1

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

1

Я никогда не использую зЬй :: for_each (или очень редко).

Я бы предложил использовать Boost.Foreach и классические конструкции «для». И когда C++ 0x отсутствует, вы можете рассмотреть возможность использования новой конструкции «для», сделанной более читаемой для итерации через контейнеры.

+1

Невозможно дождаться, когда C++ получит реальный цикл «за» (а не глорифицированный цикл while). –

0

Или вы могли бы ждать C++ 0x и использовать for(elem& e, container){e.something();}
Совершенно так же, как BOOST_FOREACH(), но часть стандарта (через несколько лет ...).

2

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

Я не могу по-настоящему оправдывать уход и создание специального класса функтора (который является умеренно продвинутой темой в C++, о которой многие мои сторонники не понимают полностью) с надлежащим конструктором и деструктором и, возможно, некоторыми аксессуарами, просто чтобы избежать однострочного цикла.

Смежные вопросы