Страницы

Поиск по вопросам

понедельник, 12 ноября 2018 г.

Использование std::find_if не для поиска

Сразу прощу прощения за такое туманное название, не знаю как в двух словах описать задачу.
Допустим у нас есть некий класс, выполняющий какую-то работу:
class Worker{ public: bool doWork(int arg); };
Метод doWork возвращает true если работа выполнена успешно. Нужно чтобы кто-то из имеющихся работников выполнил работу. Для этого хочу воспользоваться std::find_if
struct DoWork{ int arg; explicit DoWork(int arg): arg(arg) {} bool operator()(Worker &worker) const{ return worker.doWork(arg); } };
std::vector workers; //... std::find_if(workers.begin(), workers.end(), DoWork(42));
Идея такая. Алгоритм будет перебирать работников до тех пор пока один не выполнит работу или они не закончатся. Но меня терзают смутные сомнения что так делать можно. Нет ли здесь неопределенного поведения? Будет ли этот код всегда одинаково работать на разных реализациях stl?


Ответ

В требованиях к предикатам, передаваемым в std::find_if, указано, что параметр предиката не обязательно должен быть константной ссылкой, но тем не менее при этом предикату запрещается модифицировать передаваемый в него объект.
25.1 General [algorithms.general] 4 For purposes of determining the existence of data races, algorithms shall not modify objects referenced through an iterator argument unless the specification requires such modification.
Для алгоритм std::find_if как раз таки такого разрешения не дается (в отличие, скажем, от std::for_each). Как формально определяется модифицирующая операция я навскидку не скажу, но если ваша функция DoWork модифицирует элемент контейнера, то есть вероятность, что так делать формально нельзя.
Дополнительно далее там же
8 The Predicate parameter is used whenever an algorithm expects a function object (20.9) that, when applied to the result of dereferencing the corresponding iterator, returns a value testable as true. [...] The function object pred shall not apply any non-constant function through the dereferenced iterator.
Параметром std::find_if как раз является Predicate pred, т.е. эта часть уже однозначно запрещает ваш вариант, если DoWork является неконстантным членом класса Worker. Опять же, в этом определении есть свои дыры, но идея, я думаю, ясна.
Навскидку, конечно, трудно представить себе, что тут может пойти не так, если реализация специально не заточена на злостное вредительство и ловлю нарушителей стандарта...

Комментариев нет:

Отправить комментарий