为何std::lower_bound性能优于std::ranges::lower_bound?何时后者更优?
std::lower_bound与std::ranges::lower_bound的性能差异及适用场景
一、为什么std::lower_bound性能优于std::ranges::lower_bound?
在你的基准测试中,std::lower_bound(算法库版本)比std::ranges::lower_bound表现更优,核心原因在于标准库实现的优化差异:
- 旧版算法的特殊化适配:部分主流标准库(如GCC/libstdc++)对
std::lower_bound做了特殊处理——当传入关联容器(如std::set)的迭代器时,会直接调用容器自带的lower_bound成员函数(利用红黑树结构实现O(log n)复杂度查找),而非执行通用的双向迭代器线性遍历逻辑。 - Ranges版本的抽象开销:
std::ranges::lower_bound为了适配范围概念的通用抽象,需要处理更多模板参数和范围适配逻辑,部分实现中暂时没有针对关联容器做同样的委托优化;额外的抽象层也可能导致编译器优化效果略逊于旧版算法,最终性能落后。
从测试结果来看,std::set::lower_bound性能最优(直接利用容器内部结构),其次是旧版std::lower_bound(借助特殊化调用成员函数),而std::ranges::lower_bound因缺少该优化,可能退化为低效的线性遍历,导致性能差距。
二、std::ranges系列算法何时能超过数据结构自带算法?
std::ranges算法并非总是落后,在以下场景中,其性能可能反超数据结构自带的算法:
- 随机访问迭代器场景:对于
std::vector这类提供随机访问迭代器的容器,std::ranges::lower_bound和旧版算法一样执行O(log n)二分查找,且由于Ranges的现代设计,部分实现可能在编译优化上更高效,性能持平甚至略优。 - 视图(View)结合场景:当需要对过滤、转换后的子范围操作时,
std::ranges算法可直接在视图上工作,无需构造临时容器。例如用std::views::filter筛选元素后,直接调用std::ranges::lower_bound,避免了拷贝数据的开销;而数据结构自带算法只能操作原始容器,无法直接处理视图。 - 自定义范围类型场景:若使用满足Ranges概念的自定义范围类型,且其迭代器支持随机访问,
std::ranges::lower_bound可直接利用特性执行高效查找;而数据结构自带算法通常只针对自身容器优化,无法适配自定义范围。 - 流水线操作场景:Ranges算法支持链式调用,配合视图可构建高效的数据处理流水线,减少中间临时对象的创建,整体性能优于多次调用数据结构自带算法+手动处理中间结果的方式。
测试代码
#include <set> #include <ranges> #include <algorithm> std::set<int> my_set; static void RangeLowerBound(benchmark::State& state) { for (auto i = 0; i <= 1'000'000; ++i) { my_set.insert(i); } auto search{900'000}; for (auto _ : state) { auto it = std::ranges::lower_bound(my_set, search); benchmark::DoNotOptimize(it); } } BENCHMARK(RangeLowerBound); static void StdLowerBound(benchmark::State& state) { for (auto i = 0; i <= 1'000'000; ++i) { my_set.insert(i); } auto search{900'000}; for (auto _ : state) { auto it = std::lower_bound(my_set.begin(), my_set.end(), search); benchmark::DoNotOptimize(it); } } BENCHMARK(StdLowerBound); static void SetLowerBound(benchmark::State& state) { for (auto i = 0; i <= 1'000'000; ++i) { my_set.insert(i); } auto search{900'000}; for (auto _ : state) { auto it = my_set.lower_bound(search); benchmark::DoNotOptimize(it); } } BENCHMARK(SetLowerBound);
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

