std::ranges::copy_if要求目标容器预先分配足够空间或使用std::back_inserter等插入迭代器,否则写入越界;必须启用C++20标准并包含<algorithm>和<ranges>头文件。

std::ranges::copy_if 的基本用法和必要条件
std::ranges::copy_if 不会自动分配内存,它只把满足条件的元素逐个复制到目标迭代器所指位置。这意味着目标容器必须预先分配足够空间,或者你得传入一个能动态增长的插入迭代器(比如 std::back_inserter)。
常见错误是直接传入空 std::vector 的 begin(),结果写入越界或静默失败:
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dst; // 空容器
std::ranges::copy_if(src, dst.begin(), [](int x) { return x % 2 == 0; }); // ❌ dst.begin() 无效写入点
正确做法只有两种:
- 预先调整
dst大小(适合已知上界或可预估数量) - 用
std::back_inserter(dst)(最常用、最安全)
用 std::back_inserter 实现自动扩容复制
这是实际项目中最推荐的方式:无需预估大小,语义清晰,且与 std::copy_if 的传统用法保持一致。
立即学习“C++免费学习笔记(深入)”;
#include <vector>
#include <ranges>
#include <algorithm>
#include <iterator><p>std::vector<int> src = {1, 2, 3, 4, 5, 6};
std::vector<int> dst;</p><p>std::ranges::copy_if(src, std::back_inserter(dst), [](int x) { return x > 3; });</p><p>// dst 现在是 {4, 5, 6}</p><p class="aritcle_card flexRow">
<p class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/shouce/1510" title="C函数速查手册(CHM版)"><img
src="https://img.php.cn/upload/manual/000/000/001/5d6de31fedca2993.png" alt="C函数速查手册(CHM版)" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<p class="aritcle_card_info flexColumn">
<a href="/xiazai/shouce/1510" title="C函数速查手册(CHM版)">C函数速查手册(CHM版)</a>
<p>C函数速查手册(CHM版)</p>
</p>
<a href="/xiazai/shouce/1510" title="C函数速查手册(CHM版)" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</p>
</p>
注意点:
-
std::back_inserter是std::insert_iterator的特化,调用的是容器的push_back - 所有支持
push_back的容器(std::vector、std::deque、std::list)都适用 - 如果目标是
std::set或std::map,得换用std::inserter并指定插入位置
性能差异:预分配 vs back_inserter
预分配空间再用 dst.begin() 写入,理论上更快(避免多次 push_back 触发扩容重排),但前提是能较准估算数量。
std::vector<int> dst; dst.reserve(std::count_if(src.begin(), src.end(), pred)); // 先统计 dst.resize(std::count_if(src.begin(), src.end(), pred)); // 再分配 std::ranges::copy_if(src, dst.begin(), pred); // 直接写入
但要注意:
-
std::count_if遍历一次,copy_if再遍历一次 → 两趟遍历 -
std::back_inserter是一趟遍历,但可能触发多次内存重分配(对小数据几乎无感,大数据需实测) - 对于
std::vector,如果过滤后数量常超过原大小 75%,预分配收益明显;否则back_inserter更简洁可靠
常见编译错误和 C++20 要求
std::ranges::copy_if 是 C++20 引入的,必须开启对应标准:
- GCC/Clang:加
-std=c++20(-std=gnu++20也行) - MSVC:默认 VS2019 16.10+ / VS2022 支持,但需确认项目属性中 C++ 语言标准设为 C++20
典型报错:
-
error: 'copy_if' is not a member of 'std::ranges'→ 标准未启用或头文件缺失(确保含<algorithm>和<ranges>) -
error: no matching function for call to 'copy_if'→ 传了左值容器却没用视图包装?不需要,std::vector可直接传;但若传的是临时对象(如func() | std::views::filter(...)),要确保生命周期足够长
真正容易被忽略的是:所有 range-based 算法要求源范围可迭代且满足 std::ranges::input_range,而自定义类型若没正确定义 begin/end 或缺少 iterator_category,也会在这里静默失败或编译报错。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xitongjiaocheng/124030.html