代码:
#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它的工作....
有人可以解释一下为什么吗?
答案 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
答案 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 ...;
声明的情况下点击函数的末尾。
在我发布的修补程序代码中,您可以看到,如果我们从未找到匹配项,则会返回结束指针,这是报告不匹配的常用方法。