11|Ranges(一):数据序列处理的新工具
- 深入了解
- 翻译
- 解释
- 总结
C++20引入了Ranges,这是一项重大的语言特性变更,为C++函数式编程带来了巨大飞跃。传统STL在处理大规模、复杂数据时存在不足,而Ranges的出现填补了这一空白。Ranges的核心概念是range,它提供了一些工具函数,用于访问传统STL容器和Ranges视图的数据。Ranges提供了获取迭代器和获取长度的函数,使得数据处理变得更加简洁和清晰。通过对比传统STL和Ranges的代码示例,可以明显感受到Ranges的优势。Ranges的出现让C++逐渐成为了处理大规模复杂数据的新贵,对于学习Ranges的读者来说,掌握它将带来便利的数据处理方式。 Ranges还提供了获取数据指针和悬空迭代器的处理方法。通过ranges::data函数可以获取range的内部数据缓冲区指针,而ranges::dangling类型则用于编译时检测悬空迭代器,提高代码的健壮性。这得益于C++20开始支持的concepts,Ranges库充分利用了这一特性,描述不同类型的range的约束,使得代码更加健壮,不容易引发错误。 总的来说,Ranges库为C++的函数式编程带来了重大改进,让开发者可以更加方便地处理大规模复杂数据,同时通过concepts的支持,提高了代码的健壮性。对于C++开发者来说,掌握Ranges将带来更加高效和可靠的编程体验。
《现代 C++20 实战高手课》,新⼈⾸单¥59
全部留言(4)
- 最新
- 精选
- 李云龙工作中防止越界访问一般是在访问前进行if条件判断,如果没有越界才会进行访问操作。而且在代码中也会增加捕获越界访问异常的代码。 下面是我根据老师的提示写的一个Range概念:template <typename T> concept Range = requires(T container){ {std::ranges::begin(container)}; {std::ranges::end(container)}; };
作者回复: 赞
2024-01-06归属地:北京1 - peter请教老师几个问题: Q1:“假设 f(x,g) 的定义为 g(x)”,这句话表面上理解是:g(x)=f(x,g)。但好像说不通啊。f(x,g)的参数g的定义为g(x),是不是这样啊。 Q2:auto是由编译器来自动判断类型吗?(类似于弱类型语言了) Q3:迭代器与只读迭代器有什么区别?难道迭代器除了“读”还可以“写”吗? 另外,逆向迭代器,比如begin,正常是从第一个向后面遍历,那“逆向”难道会向前遍历?(已经是第一个,不可能向前遍历啊) Q3:代码的运行环境是什么样的? 对于实例代码,想运行一下看看,IDE是什么啊,包括设置编译器版本为c++20等。 Q4:“start = std::find(getArray().begin(), getArray().end(), 1);”调用后为什么会变成悬空指针?能否再详细说明一下?
作者回复: Q1:这里的意思是f(x,g)=g(x),函数f包含两个参数,x是一个普通参数,g是另一个函数。函数g的定义是g(x)=…(定义未知),所以根据函数f的定义会调用g,并将x作为参数传递给g。这里f就是一个高阶函数了。 Q2:auto是编译时自动类型推断,虽然可以减少开发者定义变量的代码量,但和弱类型语言的动态类型天差地别。弱类型语言更多的是动态类型,也就是在运行时执行后才能判断这个变量的类型(比如一个弱类型语言的函数的返回值类型可能是两个不相关的类型),而C++是强类型语言,auto的作用是在编译时根据函数的定义自动推断出类型,也就是必须要求C++编译器能够根据代码在编译时静态确定类型,C++的普通函数也不可能返回两个不相干类型,这一点在C++里是通过模板实现的,但是模板的原理也是编译时实例化模板函数实现的,这样才能编译时静态确定类型,所以auto和弱类型的动态类型是完全不同的。 Q3:迭代器的只读指的是是否能够通过迭代器去修改迭代器指向的数据,迭代器就是一个泛化的“指针”,所谓的只读迭代器就类似于const T *,可以修改迭代器,但是不能修改迭代器指向的数据。所谓的逆向迭代器就是会将序列的最后一个元素指针作为begin,这种迭代器会将对迭代器的累加操作转换为对迭代器内部指针的累减操作,实现逆向迭代。 Q4:代码的运行环境推荐Windows下的Visual C++ 2022,对C++20已有标准的兼容性是比较好的。 Q5:因为getArray返回的是一个临时对象,然后begin和end是在getArray返回的临时对象上执行的,所以begin和end执行结束后相应的临时对象都会被自动销毁,所以调用后begin和end返回的迭代器就变成了悬空的迭代器(包含悬空指针)。 如果用伪代码解释,这个过程就是: a1 = getArray(); b = a1.begin(); arg1 = b; a2 = getArray(); e = a2.begin(); arg2 = e; DESTROY(a1); DESTROY(a2); DESTROY(b); DESTROY(e); start = std::find(REF(arg1), REF(arg2), 1); 所以真的调用find的时候a1和a2都已经被销毁了,自然arg1和arg2两个迭代器就“悬空”了。
2023-02-09归属地:北京1 - Family mission#include <vector> #include <algorithm> #include <ranges> #include <iostream> int main() { namespace ranges = std::ranges; auto getArray = [] { return std::vector{ 0, 1, 0, 1 }; }; // 编译成功 auto start = std::find(getArray().begin(), getArray().end(), 1); std::cout << *start << std::endl; // 编译失败 auto rangeStart = ranges::find(getArray(), 1); std::cout << *rangeStart << std::endl; return 0; } 这个代码块中auto getArray = [] { return std::vector{ 0, 1, 0, 1 }; };编译器会报错,需要改成 auto getArray = [] { return std::vector<int>{ 0, 1, 0, 1 }; };才可以
作者回复: 提供下一下使用的编译器和具体版本~
2023-12-13归属地:上海 - 努力学习不准懈怠#include <vector> #include <algorithm> #include <ranges> #include <iostream> int main() { namespace ranges = std::ranges; // 首先,调用ranges::begin和ranges::end函数获取容器的迭代器 // 接着,通过迭代器访问数据中的元素 std::vector<int> v = { 3, 1, 4, 1, 5, 9, 2, 6 }; auto start = ranges::begin(v); std::cout << "[0]: " << *start << std::endl; auto curr = start; curr++; std::cout << "[1]: " << *curr << std::endl; std::cout << "[5]: " << *(curr + 3) << std::endl; auto stop = ranges::end(v); std::sort(start, stop); // 最后,调用ranges::cbegin和ranges::cend循环输出排序后的数据 for (auto it = ranges::cbegin(v); it != ranges::cend(v); ++it ) { std::cout << *it << " "; } std::cout << std::endl; return 0; } 这段代码第19行应该是std::cout << "[4]: " << *(curr + 3) << std::endl;
作者回复: 恩,这里应该改成[4]。 已修正。
2023-02-22归属地:安徽