std::remove_if 不会删除所有项目

het*_*fan 5 c++ algorithm

在输入中我想删除所有非唯一值。我希望删除双项后的子集与输入相同。不知何故,某些字符保留在输入中,但并非所有字符都被删除。谓词内的 std::map 的大小似乎也在减小。

我使用的 std::remove_if() 谓词是:

template<class T>
class RemovePredicate {

    public:

        RemovePredicate() : m_oldsize(0) {}

        bool operator()(const T& value)
        {
            //
            bool retval;
            m_uniques[value] ='a'; // 'a' could be any value
            cout << m_uniques.size() << endl;
            retval = m_uniques.size() == m_oldsize;
            m_oldsize = m_uniques.size();
            return retval;
        }

    private:

        std::map<T, char>   m_uniques;
        unsigned            m_oldsize;

};
Run Code Online (Sandbox Code Playgroud)

我设计谓词的方式是,当我看到大小增加时,我还没有遇到输入。因此,当大小不同时,我不会删除输入。当大小保持不变时,我再次遇到该输入值,然后我将其删除。

测试这个的代码是:

template<class T>
void print(T iterable)
{
    for (auto c : iterable)
        cout << c;
    cout << endl;
}


int main(int argc, char** argv){
    if (argc != 2)
        return 1;

    char * str= argv[1];

    vector <char> charvec (str, str + strlen(str));
    print(charvec);

    auto itend = std::remove_if(charvec.begin(),
                                charvec.end(),
                                RemovePredicate<char>()
                                );
    print(charvec);
    // apply erase remove idiom
    charvec.erase(itend, charvec.end()); 
    print(charvec);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输入示例是:

./remove_duplicates 死牛肉

输出给出

德阿贝夫

但正如您所看到的,输出中仍然有一个双“e”。但好的一面是,原来的顺序被保留了。

我究竟做错了什么?

Ben*_*igt 5

无法保证对谓词的每次调用都是在函数对象的同一副本上进行的。

您需要安排副本共享单个map(或setunordered_set),例如通过在更广泛的范围内声明map并保留引用,或者通过使用shared_ptr(因此函数对象作为一个组仍然拥有它)。

  • @hetepeperfan:所有人都是如此。C++ 标准在 §25.1/10 中明确指出,*“除非另有说明,否则以函数对象作为参数的算法允许自由复制这些函数对象。对于对象身份很重要的程序员来说,应该考虑使用指向非复制的实现对象,例如 `reference_wrapper&lt;T&gt;` (20.9.4),或一些等效的解决方案。"* (2认同)