Ranges::views 如何实现 O(1) 复杂度?

问题描述

在最近引入的 C++20 Ranges 中,我知道 views 通过使用视图适配器实现可组合性。我也知道视图不拥有它们的元素,并且它们的性质是惰性的,也就是说它们只在需要时才进行实际计算。

视图如何在移动、复制和分配操作上实现 O(1) 复杂性?对我来说可能的答案是,视图只是“待计算”操作的描述,它们只是指数据及其转换。

不过,听起来好像视图只是承担了表达我们的编码序列的工作,并且只有在传递给某些急切的东西(例如算法)时,它们才会在这个特定的单个调用中体现所有计算负载

>

后续问题:我可以理解如何实现O(1)复制,本质上是指可复制对象(虽然我不知道这是否是{{ 1}} 做)。但我无法理解这将如何在分配操作中发挥作用。同样,一个可能的答案是,因为所有这些都发生在编译时,那么再次“描述”赋值是一个 ranges::views 操作。但是改变一个被视图查看的 O(1)一个运行时操作(很棒的 example)。这仍然是 std::vector<int> 操作吗?

解决方法

您认识到视图不拥有它们引用或操作的元素。但是您似乎不明白这就是为什么这些操作是 O(1)。

如果你有这个:

vector<int> v = {...};
auto *vptr = &v;

auto *vptr2 = vptr;
vptr = vptr2;

vref2 相对于 v.size() 的初始化复杂度是多少? vptr 相对于 v.size() 的赋值复杂度是多少?

它们都是 O(1) 因为它们只是复制指针

vptr 指向 v;它不拥有它。成为一个指针是如何它不拥有v。这也是复制指针是 O(1) 操作的方式:因为指针的大小并不关心它指向的数据的大小。

视图也是如此。视图类型存储基础范围的迭代器/哨兵。指针是一种迭代器,但迭代器的工作方式很像指针,因为它们指向一个值序列,而不是序列本身。范围由起始迭代器和表示该范围结束的值(有时是另一个迭代器,有时是可以针对迭代器进行测试的通用对象)定义。

迭代器类型不知道也不关心序列中有多少元素。迭代器概念对序列中的位置进行建模;从概念上讲,它不知道终点是什么。

因此复制迭代器(通常)相对于它们指向的范围的大小是 O(1)。移动和复制/移动分配也是如此。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...