C ++ 11 equal_to和更少

时间:2014-07-16 15:03:14

标签: c++ c++11 stl

代码:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template<typename T, typename C> T pfind(T f, T e, C c){
    do{
        for (int i = 1; f + i != e; i++)
            if (c(*f, *f + i))
                return (f + i);
    } while (++f != e);
}

int main()
{
    vector<int>vstr = { 1, 2, 3, 4,4,5,5,5 };

    vstr.erase(pfind(vstr.begin(), vstr.end(),equal_to<int>()));
    for (auto&itr : vstr){
        cout << itr << " ";
    }
    getchar();
}

此代码崩溃......

但是当我尝试使用less而不是equal_to它的工作....

有人可以解释一下为什么吗?

2 个答案:

答案 0 :(得分:2)

如果你注意编译器警告,你就已经知道你的功能失败了。当您将std::equal_to作为比较谓词传递时,它找不到匹配项(由于代码中的错误)。

如果找不到匹配项,则函数结束时不返回任何内容,这是未定义的行为。随后在调用vector::erase时使用此不存在的返回值会导致崩溃。


由于这种情况,您的代码无法找到匹配项:

if (c(*f, *f + i))

您首先取消引用迭代器,然后将i添加到该结果中。你真正想做的是

if (c(*f, *(f + i)))

然后在函数末尾添加一个return语句,用于未找到匹配项的情况。

return e; // return the end iterator

最后,您的整个函数可以替换为std::adjacent_find,它会搜索满足指定条件的两个相邻元素的范围。两个参数版本使用operator==来执行比较,而您可以使用三个参数版本提供二元谓词。使用此功能,您的示例将缩小为

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
    vector<int>vstr = { 1, 2, 3, 4,4,5,5,5 };

    vstr.erase(std::adjacent_find(vstr.begin(), vstr.end()));
    for (auto&itr : vstr) {
        cout << itr << " ";
    }
}

输出:

  

1 2 3 4 5 5 5

Live demo

答案 1 :(得分:1)

所以,在评论中,Alessandro Teruzzi有关键点。

  

你确定你的意思是c(*f,*f+i)而不是c(*f,*(f+i))吗?

但话虽如此,这可以更清楚地写成两个嵌套for循环,并且更长的变量名称

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template<typename T, typename C> T pfind(T begin, T end, C comparator){
    for (int i = 0; begin + i != end; ++i)
        for (int j = i+1; begin + j != end; j++)
            if (comparator(begin[i], begin[j]))
                return (begin + i);
    return end;
}

int main()
{
    vector<int>vstr = { 1, 2, 3, 4,4,5,5,5 };

    vstr.erase(pfind(vstr.begin(), vstr.end(),equal_to<int>()));
    for (auto&itr : vstr){
        cout << itr << " ";
    }
    getchar();
}

我们也可以使用迭代器直接编写pfind()函数:

template<typename T, typename C> T pfind(T begin, T end, C comparator){
    for (; begin != end; begin++)
        for (T iterator = std::next(begin); iterator != end; iterator++)
            if (comparator(*begin, *iterator))
                return begin;
    return end;
}

此外,在这两种情况下,我们都有可能返回结束指针。如果我们这样做,那么我们将调用vstr.erase(vstr.end()),这是未定义的行为。所以你可能想检查一下。

让我们谈谈特定警告的含义:

在评论中你说编译器报告了这个警告:

main.cpp:13:1: warning: control may reach end of non-void function [-Wreturn-type] 

这意味着编译器无法确保代码中的所有路径都以语句结尾return ...;在您的情况下,在最简单的情况下,如果begin == end,则第一个循环将没有输入,我们将在没有达到return ...;声明的情况下点击函数的末尾。

在我发布的修补程序代码中,您可以看到,如果我们从未找到匹配项,则会返回结束指针,这是报告不匹配的常用方法。