sのベクトルから重複する値を削除したいとしますint
。通常の解決策は、ベクトルをソートし、erase-removeイディオムを使用して重複を消去することです。ただし、削除されない要素の順序を維持する必要があるため、並べ替えることはできません。したがって、次のような述語を考え出し、remove_if
アルゴリズムで使用することができます。
struct comp {
std::set<int> s;
comp() : s() {}
bool operator()(int i)
{
return !(s.insert(i)).second;
}
};
set
ただし、メンバーのコピーが2つ取得されるため、何らかの理由で述語オブジェクトがコピーされると、これは機能しなくなります。そして確かに、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;
しかし、疑問は残ります:
述語ファンクターの可能なコピーがロジックを壊さないことを確認する必要がありますか? この問題に関して特定の動作を義務付ける(または禁止する)規格には何かありますか?それとも、実装のバグですか?