使用std::for_each()和std::bind()过滤vector元素存入新vector失效问题
问题根因
问题出在std::bind的默认参数传递逻辑:
std::bind会对所有非占位符的传入参数做值拷贝,你写的bind(mypred, placeholders::_1, 3, final)会直接复制一份final向量生成临时副本,后续mypred函数里对参数c的所有修改(包括push_back插入元素)全都是在这个临时副本上操作的。for_each执行完成后,这个临时副本会立刻销毁,main函数里定义的原始final向量从头到尾没有被修改过,自然是空的。- 你能看到两次
yes打印,是因为1、2两个元素确实满足a < 3的判断条件,打印逻辑正常执行了,只是插入的元素全留在了被销毁的临时副本里,没有同步到原向量。
修复方案
要让bind持有原向量的引用而不是拷贝副本,只需要用std::ref()把传入的final包裹起来即可,修正后的完整代码如下:
#include <iostream> #include <vector> #include <algorithm> #include <functional> // 提供std::bind、std::ref、占位符支持 using namespace std; void mypred(int a, int b, vector<int>& c){ if(a < b){ cout <<"yes" << endl; c.push_back(a); } } int main(){ vector<int> test = {1,2,3,4,5,6,7}; vector<int> final; final.reserve(10); // 用std::ref包装final,强制按引用传递原向量 for_each(test.begin(), test.end(), bind(mypred, placeholders::_1, 3, ref(final))); for(auto i = final.begin(); i != final.end(); i++){ cout << *i << endl; } return 0; }
运行修正后的代码,会正常打印两次yes,最终遍历final时能正确输出1、2两个元素。
如果是写现代C++(C++11及以后版本),更推荐直接用lambda替代std::bind,不需要记特殊的传参规则,捕获逻辑更直观,不容易出类似的拷贝问题:
// 替换原来的for_each行即可 for_each(test.begin(), test.end(), [&final](int a) { if (a < 3) { cout << "yes" << endl; final.push_back(a); } });
内容的提问来源于stack exchange,提问作者Kevin eyeson
相关产品推荐
相关产品推荐

