Предположим, мы хотим удалить повторяющиеся значения из вектора int
s. Обычное решение состоит в том, чтобы отсортировать вектор и стереть дубликаты с помощью идиомы «стереть-удалить». Но нам нужно поддерживать порядок элементов, которые не будут удалены, поэтому мы не можем сортировать. Таким образом, можно придумать такой предикат и использовать его с алгоритмом remove_if
:
struct comp {
std::set<int> s;
comp() : s() {}
bool operator()(int i)
{
return !(s.insert(i)).second;
}
};
Но это сломается, если объект предиката будет по какой-то причине скопирован, так как мы получим две копии члена set
. И действительно, реализация gcc remove_if
делает именно это:
template<typename _ForwardIterator, typename _Predicate>
_ForwardIterator
remove_if(_ForwardIterator __first, _ForwardIterator __last,
_Predicate __pred)
{
__first = _GLIBCXX_STD_A::find_if(__first, __last, __pred);
if(__first == __last) // ^^^^^ here a copy is made
return __first;
_ForwardIterator __result = __first;
++__first;
for(; __first != __last; ++__first)
if(!bool(__pred(*__first)))
{
*__result = _GLIBCXX_MOVE(*__first);
++__result;
}
return __result;
}
Обходной путь состоит в том, чтобы сделать set
членом нашего функтора статическим:
struct comp {
static set<int> s;
comp() { s. clear(); }
bool operator()(int i)
{
return !(s.insert(i)).second;
}
};
set<int> comp::s;
Но остается вопрос:
Нужно ли нам убедиться, что возможная копия предикатного функтора не нарушит нашу логику? Есть ли в стандарте что-либо, предписывающее (или запрещающее) определенное поведение в отношении этой проблемы? Или это ошибка в реализации?