C++如何使用 std::ranges::copy?if 条件式过滤数据并将结果存入容器

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

c++如何使用 std::ranges::copy_if 条件式过滤数据并将结果存入容器

std::ranges::copy_if 的基本用法和必要条件

std::ranges::copy_if 不会自动分配内存,它只把满足条件的元素逐个复制到目标迭代器所指位置。这意味着目标容器必须预先分配足够空间,或者你得传入一个能动态增长的插入迭代器(比如 std::back_inserter)。

常见错误是直接传入空 std::vectorbegin(),结果写入越界或静默失败:

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_inserterstd::insert_iterator 的特化,调用的是容器的 push_back
  • 所有支持 push_back 的容器(std::vectorstd::dequestd::list)都适用
  • 如果目标是 std::setstd::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

C++如何使用std::to?chars进行极高性能的数值/浮点数转格式输出
上一篇 2026-07-01 16:26
C++如何使用std::ranges::sort对自定义类/结构体容器进行高性能排序
下一篇 2026-07-01 16:26

相关推荐