std::ranges::copy_if需包含<algorithm>和容器头文件,C++20起可用,要求编译器开启C++20模式;它不修改源范围,仅按谓词筛选元素写入目标迭代器,目标空间须预先分配足够容量,否则行为未定义。

std::ranges::copy_if 的基本用法和必要头文件
必须包含 <algorithm> 和 <vector>(或其他容器头文件),C++20 起 std::ranges::copy_if 才可用,且要求编译器开启 C++20 模式(如 g++ -std=c++20)。它不修改源范围,只按谓词筛选元素并逐个写入目标迭代器——目标空间必须预先分配足够容量,否则行为未定义。
常见错误是直接传入空 std::vector 的 begin(),结果写入野指针:
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dst; // ❌ 空容器,dst.begin() 无效
std::ranges::copy_if(src, dst.begin(), [](int x) { return x % 2 == 0; });
正确做法是预先 resize 或用 back_inserter:
- 若已知最大可能数量,
dst.resize(src.size())后用dst.begin() - 更常用:配合
std::back_inserter(dst),自动 push_back
如何配合 std::back_inserter 避免越界风险
std::back_inserter 是最安全的默认选择,尤其当过滤后元素数量未知时。它包装目标容器的 push_back,每次写入都自动扩容。
立即学习“C++免费学习笔记(深入)”;
示例:
std::vector<int> src = {1, 2, 3, 4, 5, 6};
std::vector<int> dst;
std::ranges::copy_if(src, std::back_inserter(dst), [](int x) { return x > 3; });
// dst 现在是 {4, 5, 6}
注意:std::back_inserter 要求目标容器支持 push_back(如 std::vector、std::deque),不适用于 std::array 或原生数组。
- 对
std::array,只能用预分配 + 普通迭代器,且需确保长度足够 - 对原生数组,传入数组名(退化为指针)+ 显式长度限制,例如
dst_ptr和dst_ptr + N
谓词写法与常见陷阱:引用捕获、副作用、返回类型
谓词必须可调用、返回能隐式转换为 bool 的值。Lambda 是最常用形式,但要注意变量捕获方式。
典型坑点:
- 误用
[&]捕获局部临时对象(如函数参数中的std::string),导致悬垂引用 - 谓词中修改外部状态(如计数器),在并行执行(
std::ranges::copy_if当前不并行,但未来可能扩展)或重排序下不可靠 - 返回非
bool类型(如int)虽能编译,但语义易混淆,建议显式return true / false
推荐写法:
std::vector<std::string> words = {"cat", "dog", "elephant"};
std::vector<std::string> long_words;
// ✅ 值捕获,安全
std::ranges::copy_if(words, std::back_inserter(long_words),
[min_len = 4](const std::string& s) { return s.length() >= min_len; });
性能考虑:目标容器类型与内存分配策略
用 std::back_inserter 时,std::vector 可能多次 realloc;若预估过滤比例(比如约 30% 保留),先 reserve 能减少扩容次数:
dst.reserve(src.size() / 3); // 预留空间,避免反复分配
而 std::deque 对 push_back 更友好,但随机访问慢;std::list 插入快但缓存不友好。实际选型取决于后续是否需要遍历、索引或迭代器稳定性。
另一个隐藏成本:谓词调用开销。如果过滤逻辑复杂(如正则匹配),考虑提前计算并缓存结果,或改用 std::ranges::filter_view 延迟求值——但注意它不“存储”结果,只是视图。
真正要存结果,std::ranges::copy_if 是明确、可控的一步到位操作;想链式处理再落地,才需要组合 filter_view + std::ranges::to(C++23)。


















