понедельник, 15 апреля 2024 г.

[prog.c++.wtf] Один из самых странных паттернов в коде, с которым доводилось сталкиваться...

В течении последнего года, может быть чуть меньше, регулярно стал натыкаться в разных кодовых базах на паттерны вроде вот такого (внимание на тело цикла for):

bool does_contain_apropriate_item(
   const item_container & items,
   const search_criteria & search_params)
{
   for(const auto & i : items) {
      if(!does_meet_coditions(i, search_params)) {
         continue;
      }

      return true;
   }

   return false;
}

Зачем нужен continue в цикле и почему нельзя сразу написать:

bool does_contain_apropriate_item(
   const item_container & items,
   const search_criteria & search_params)
{
   for(const auto & i : items) {
      if(does_meet_coditions(i, search_params))
         return true;
   }

   return false;
}

Большая и неразрешимая для меня загадка.

Возможно, выросло поколение, которое лояльно относится к break/continue в циклах. А может уже и не одно поколение.

PS. Почему не используется в таких случаях std::find_if -- это отдельный вопрос. Местами не такой простой, как может показаться. Тем более, что я привел не реальный фрагмент кода, а общую схему того, что вижу в последние месяцы регулярно. Детали же часто сильно отличаются, иногда еще нужен и индекс найденного элемента, так что на практике std::find_if не всегда такая уж удобная замена.

4 комментария:

Stanislav Mischenko комментирует...

> иногда еще нужен и индекс найденного элемента, так что на практике std::find_if не всегда такая уж удобная замена.
Вот тут я что-то не понял. find_if возвращает итератор, следовательно индекс равен index = find_if(begin(v), end(v)) - begin(v). Конечно контайнер может не поддерживать random access, но тогда такое понятие как "индекс" будет неуместно.

eao197 комментирует...

> Конечно контайнер может не поддерживать random access, но тогда такое понятие как "индекс" будет неуместно.

Тем не менее, бывают случаи, когда у нас что-то вроде std::list и нужно не просто найти есть ли искомый элемент или нет, но и его порядковый номер. Типа того, что "запрос с параметрами XYZ стоит в очереди под номером 5". Если мы сперва найдем элемент и получим итератор на него, а затем попробуем вычислить индекс через std::distance, то у нас получится двойной забег по std::list.

aensidhe комментирует...

Это странно, конечно. Я обычно использую паттерн с continue, если тело цикла большое.

eao197 комментирует...

> Это странно, конечно.

Да не то слово.

> Я обычно использую паттерн с continue, если тело цикла большое.

В больших циклах-то понятно. Я же именно про случаи, когда циклы короткие, и про случай, когда проще сделать один if(condition), чем if(!condition) continue; + еще что-то.

Хотя я вообще негативно к continue отношусь. Гораздо хуже, чем к break-у.