1. 理解ranges视图缓存的本质
第一次在C++20标准中看到ranges视图时,我像发现新大陆一样兴奋。但很快在实际项目中遇到了性能问题——当我连续多次遍历同一个视图时,每次都要重新计算,这对性能敏感的场景简直是灾难。这就是视图缓存要解决的核心问题。
视图(view)是ranges库的核心抽象之一,它代表一个惰性求值的序列。与容器不同,视图不拥有数据,只是提供数据的"视图"。比如:
cpp复制auto nums = std::vector{1,2,3,4,5};
auto even = nums | std::views::filter([](int n){ return n%2==0; });
这里的even就是一个视图,它不会立即计算所有偶数,而是在遍历时才逐个判断。这种惰性特性带来了性能优势,但也意味着每次遍历都会重新计算。
视图缓存的核心思想很简单:第一次遍历时把结果保存下来,后续直接使用缓存。这特别适合以下场景:
- 视图计算成本高(如复杂过滤或转换)
- 需要多次遍历同一视图
- 视图数据在两次遍历间不会改变
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 实现视图缓存的三种方式
2.1 手动缓存到容器
最直接的方式是将视图结果保存到容器:
cpp复制auto cached = std::vector(even.begin(), even.end());
优点:
- 简单直接,任何C++版本都可用
- 完全控制缓存生命周期
缺点:
- 需要额外存储空间
- 需要手动管理缓存更新
提示:如果原始数据可能改变,需要重新生成缓存。这时可以用
std::vector的assign方法更新内容。
2.2 使用ranges::cache_latest
C++23引入了cache_latest适配器,它自动缓存最近访问的元素:
cpp复制auto cached_view = even | std::ranges::views::cache_latest;
这个适配器会:
- 在首次访问元素时缓存
- 下次访问相同位置直接返回缓存
- 只缓存最近访问的一个元素
适合场景:
- 随机访问少量元素的视图
- 需要部分缓存而非全部的情况
2.3 自定义缓存适配器
对于更复杂的需求,可以自定义
