C ++迭代器认为有害?
在今天的Boost图书馆大会上,“现代C ++devise”和Loki C ++图书馆的作者Andrei Alexandrescu就“迭代器必须去”( video , 幻灯片 )这个话题做了一个演讲,讨论迭代器为什么不好,他有一个更好的解决scheme。
我试图阅读演示幻灯片,但是我无法从中得到很多。
- 迭代器是坏的?
- 他的replace是否真的更好?
- C ++实现者会提出他的想法吗?
首先,回答你的问题:
- 不。事实上,我在别处争辩说,迭代器是有史以来计算机科学最重要/最基本的概念。 我(不像Andrei)也认为迭代器是直观的 。
- 是的,当然,但这不应该是一个惊喜。
- 嗯。 看Boost.Range和C ++ 0x – 他们已经不是?
Andrei在这里的重要贡献就是:完全放弃迭代器的概念,将范围看作是一个便利的包装,而不是一个核心构造。 其他语言已经做到了这一点(Andrei的许多概念只是回应了.NET的LINQ或者Python的迭代器),但是它们都只提供输出范围 。 Andrei主张不同types的范围,就像传统的迭代器类别一样。
有鉴于此,他开始嘲笑这些迭代器类别的随意性,这很奇怪。
我也认为他的例子是closures的,尤其是他的文件复制:是的,迭代器变种是比1975年的代码大大改善。 它将复杂的中断条件下的循环减less到一个语句。 他真正需要解决的问题就是语法。 那么对不起,我们在这里讨论C ++ ,当然这个语法是丑陋的。 是的,在这里使用范围是一个改进 – 但仅在语法上。
我也认为安德烈的find
是closures的。 他真正定义的是来自LINQ的DropUntil
操作(命名很难!)。 find
操作应该返回一个或零个元素(或一个迭代器!)。 在这里回避迭代器在我看来是没有帮助的,因为我们可能想要直接修改值而不是复制它。 在这里返回一个元素的范围只会增加没有好处的开销。 这样做安德烈的方式是不好的,因为那么方法的名字是错误的,误导。
也就是说,我基本上都同意安德烈的观点。 迭代器虽然是我的计算机科学的宠物概念,但它肯定是一个很大的语法负担,许多范围(特别是无限生成器)可以(也应该)在没有它们的情况下方便地实现。
- 我们大多数人在已经熟知的习惯用法中简单地使用它们,比如for循环遍历std :: vector。 开发人员阅读并知道发生了什么事情。 在我们日常的编码生活中,迭代器不好或不好,它们只是“完成工作的原因”。
- 可能是。
- 我不这么认为。
安德烈有时可能会有点挑衅。 迭代器是一个合理的概念,在比特的意义上是非常基本的。 但是就像C ++中的大多数位不是bools,而是更大types的一部分,大多数迭代器应该在高层处理。 安德烈是正确的,适当的水平这样做是范围对象。 但是并不是所有的范围都被正确地暴露为迭代器范围,如istream_iterator sentinel所示。 这只是一个创build一个人造的最终迭代器的黑客。 不过,我认为他的想法不会被实现所取代。 C ++ 1x将与C99相关。
我同意他的观点,迭代器大多不如范围,我不知道是否有更好的东西会被拾起。
“好的是最好的敌人”在这里扮演着强有力的angular色,就像往常一样。 迭代器是有用的,并且牢固的根深蒂固,所以很难知道像范围这样的更好的东西能否在合理的时间内取代它们。
C ++ 0x已经开始了第一步:
- 右值引用解决了将容器作为范围处理的一些问题
- 范围已被添加到核心库,包括范围概念
在不丢失任何迭代器function的情况下(考虑到迭代器类别,常量和右值的所有组合),转换到范围非常困难,特别是如果试图考虑无限和可变范围。
-
不,他们并不坏,他们实际上是非常聪明的想法。 但是,它们并不理想,在迭代器的概念上还有改进的空间。
-
它用迭代器解决了现实生活中的问题。 例如,在很多情况下,从单个容器中查询两个单独的对象(迭代器),然后将它们仍然作为两个单独的对象传递给一个algorithm,这是很乏味的(也是容易出错的)。 为什么不传递一个单一的对象? 即使是
std::pair<iterator, iterator>
也会使粗略的范围更容易操作 – 一个对象,而不是两个。 另外,考虑a range is an iterator
个好主意。 事实上,安德烈所说的就是这个。 顺便说一句,这些问题已经被Boost.Range解决了。 -
我预料会发生,但不会是革命,而是进化。
我认为我们应该在迭代器旁边使用范围,即我们应该select进化方式,而不是革命方式。
是不是Andrei试图为D语言做一些隐藏的营销(目前他正在与之合作)…?
Andrei指出容器是可以的,但迭代器是丑陋的,非直观的,容易出错和危险的,很难实现(这个最后一个似乎是相当真实的…)我们在C ++中有什么…指针? 他们难道不是很丑吗? 但我们高兴地拥抱他们并与他们同住。
哪一个更直观写:
for(auto i=foo.begin();i!=foo.end();++i) bar(*i);
要么
for (auto r=foo.all(); !foo.empty(); foo.popFront()) bar(r.front());
迭代器的概念可以用范围和其他想法来补充,但我认为它们有它们的位置,不会被replace。
- 有时
- 大概
- 不太可能,至less不是很多年
像任何API或function一样,如果滥用可能会造成很多识别困难的问题。 迭代器在许多项目中都有使用,但是始终根据其特性保持必要的关怀。 在使用它之前,应该先了解它们的局限性。 如果用户正确的话,迭代器会非常有用。
这个问题是相关的:
有什么办法来检查迭代器是否有效?
我应该喜欢比const_iterators迭代器?
我不同意安德烈和康拉德和我自己:-)
最基本的概念是一个接口,不是一个迭代器,在任何人现在做的任何工作中都是非常明显的(这是关于跨库,跨语言,交叉编译,跨操作系统,跨平台,交叉名称它:-)
迭代器或范围(除源代码级别的用法之外)不仅仅提供简洁,非侵入性或侵入性,非共享性或共享性,非唯一性或唯一性指针! 清理指向types化数据的指针是简单的通用的,你可以使数据可变或不可变以及许多其他的东西。 所有的接口对它来说只是间接的另一个级别,对各种机器和编译器仍然很友好,再加上安全性更高,将迭代器和范围使用降级到实现细节。
就这一点来说,IEnumerable和IQueryable做了一半的“正确的事情”,但是它们在迭代的概念上显然是低劣的,而且更多的是你可以用STL做什么,保留控制等等(但是,它们有更好的元数据因此是一个更好,更清洁的模型)。 指向接口,你可以build立任何你想要的和抽象的概念,很可能是矛盾的,但本质上是一个很好的,最优化的,运行时或编译时中立的数据表示和代码(对于algorithm,编译器和虚拟机是不可或缺的) 。
甚至可以将“dynamic”/组件系统优化到“运行时间”内联(HotSpot VM :-)。从这个意义上说,到1975年为止,进展非常缓慢,你看,包括这个网站,它使用专有和开放技术等;在计算机科学理想主义,那么这种types的接口“工作”不应该存在)。
我认为C ++实现者将会完全为C ++ 0x提供完整的工作支持,而不需要实现新的非标准范例。
我从演示中可以看到的唯一参数是无法定义范围,并且c ++ 0x“范围for语句”提议似乎在某种程度上消除了这个问题。 也许它不应该是一个争论,如果应该/不应该使用迭代器,但更多的情况应该/不应该被用于?