std::ranges、std::views和懒加载

1、std::string::npos是C++中std::string类定义的一个静态常量,通常用于表示"未找到"或"直到字符串结束"。

常见用途:

表示查找操作,但未找到结果

cpp 复制代码
std::string str = "hello word";
size_t pos = str.find("xyz");
if(pos == std::string::npos)
{
    //查到结尾,但未找到
}

表示从某个位置开始,截取到字符串末尾

cpp 复制代码
std::string str = "hello world";
std::string sub = str.substr(6,std::string::npos);
//表示从位置6开始,截取到字符串末尾

2、惰性视图:是一种优化程序性能的编程技术。它的核心理念是:把要做的工作记录下来,但不立即执行,等到需要结果的那一刻,才进行真正的计算。

3、C++20引入的Ranges库是标准库模板STL的一次重大升级,它通过"视图"和"管道符 |"提供了一种更现代、更强大、也更安全的数据处理方式。

核心概念,Ranges库建立在几个相互关联的核心概念之上:

(1)范围:一个可以遍历的元素序列的抽象。如标准容器库vector,list,array等都是范围

(2)视图:一个轻量级的、非持有的范围,它不会复制数据,而是对底层数据进行某种操作(如筛选、转换等)并提供一个"视图"。视图的计算是惰性的,即只有在需要时才计算,这为性能优化提供了巨大空间。

(3)范围适配器:返回视图的函数或对象。它们是构建数据处理管道的基本单元,通过管道符 | 进行组合,数据从左向右流动,逻辑清晰直观。

(4)管道符:用于组合视图的操作符。R | A | B的写法让数据处理像流水线一样易于理解。

Ranges库并非仅仅是语法糖,它代表了一种全新的、更函数式的C++编程范式。

cpp 复制代码
#include <string>
#include <vector>
#include <algorithm>
#include <ranges>
#include <iostream>
int main()
{
	std::string word = "apple";
	auto hasWord = [&word](const std::string& s) {return s.find(word) != std::string::npos;};
	std::vector<std::string> words = { "apple pie", "banana split", "apple tart", "cherry cobbler" };
	auto res = words | std::views::filter(hasWord);

	for (auto s : res)
	{
		std::cout << s << std::endl;
	}

	std::vector<int> input{0,1,2,3,4,5,6,7,8,9,10};
	std::vector<int> intermediate, output;
	std::copy_if(input.begin(), input.end(), std::back_inserter(intermediate), [](int i) {return i % 3 == 0; });
	std::transform(input.begin(), input.end(), std::back_inserter(output), [](const int i) {return i * i; });
	for (auto i : intermediate)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;
	for (auto i : output)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;

	auto output2 = input | std::views::filter([](const int i) {return i % 3 == 0; });
	auto output3 = input | std::views::transform([](const int i) {return i * i; });
	for (auto i : output2)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;
	for (auto i : output3)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;
	auto output4 = input | std::views::filter([](const int i) {return i % 3 == 0; }) | std::views::transform([](const int i) {return i * i; });
	std::cout << "------------------" << std::endl;
	for (auto i : output4)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;
	return 0;
}

4、管道的作用

左边:数据源(容器、范围)

右边:视图适配器

效果:将数据源"喂给"视图适配器处理

5、懒加载的具体体现

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <ranges>

int main() {
    std::vector<std::string> words = { "apple pie", "banana split", "apple tart" };

    int filterCalls = 0;
    auto hasApple = [&filterCalls](const std::string& s) {
        filterCalls++;
        std::cout << "Filter checking: " << s << std::endl;
        return s.find("apple") != std::string::npos;
        };

    // 创建视图 - 不会触发任何过滤检查
    auto view = words | std::views::filter(hasApple);
    std::cout << "After view creation, filter calls: " << filterCalls << std::endl;

    // 第一次遍历 - 触发过滤
    std::cout << "\nFirst iteration:\n";
    for (const auto& s : view) {
        std::cout << "  Result: " << s << std::endl;
    }
    std::cout << "Filter calls after first iteration: " << filterCalls << std::endl;

    // 第二次遍历 - 再次触发过滤
    std::cout << "\nSecond iteration:\n";
    for (const auto& s : view) {
        std::cout << "  Result: " << s << std::endl;
    }
    std::cout << "Filter calls after second iteration: " << filterCalls << std::endl;
}

与普通容器相比:

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <ranges>

int main() {
    std::vector<std::string> words = {"apple pie", "banana split", "apple tart"};
    
    // 方式1:立即求值的传统方式
    auto hasApple = [](const std::string& s) {
        return s.find("apple") != std::string::npos;
    };
    
    std::vector<std::string> eager_result;
    std::copy_if(words.begin(), words.end(), 
                 std::back_inserter(eager_result), 
                 hasApple);
    // eager_result 现在就包含了所有匹配的字符串(副本)
    
    // 方式2:惰性求值的视图方式
    auto lazy_view = words | std::views::filter(hasApple);
    // lazy_view 不包含数据,只是知道如何过滤
    
    // 主要区别:
    // 1. 内存:eager_result 占用额外内存,lazy_view 不占用
    // 2. 时间:eager_result 立即计算,lazy_view 延迟计算
    // 3. 原数据修改:lazy_view 会反映原数据的变化
}
相关推荐
Ivanqhz8 分钟前
Ping-Pong 双缓冲
开发语言·人工智能·python·深度学习·mlir
m0_7345717611 分钟前
深入理解C++ RAII
开发语言·c++
泡海椒14 分钟前
jquick-pdf 表格实战:动态数据 PDF 报表生成
java·开发语言·pdf
aramae23 分钟前
模拟实现memset()(C语言)
c语言·开发语言·后端
hetao173383733 分钟前
2026-09-18 hetao1733837 的刷题记录
c++·算法
wuyk5551 小时前
【Socket 进阶之路】第 7 章 IO 多路复用 select & poll 完整实战|多 fd 监听、超时等待、优缺点横向对比
服务器·开发语言·网络·数据库·物联网
stolentime1 小时前
CSP-J2026第一轮试题(附答案解析、markdown源码)
c++·csp
船厂电气自动化ai大模型1 小时前
AI大模型与数学|第81天 课程:正交向量、正交基、格拉姆‑施密特(Gram‑Schmidt)正交化
开发语言·数据结构·人工智能·线性代数·机器学习
Rabitebla1 小时前
【Linux系统编程】 指令(二):一条路径是怎么定位到文件的
linux·c++·笔记·学习·算法
lv__pf2 小时前
seata【实战 msb】
java·开发语言·后端