【问题标题】:Why isn't there an operator[] for a std::list?为什么 std::list 没有 operator[]?
【发布时间】:2010-11-09 21:48:20
【问题描述】:

谁能解释一下为什么没有为 std::list 实现 operator[] ?我搜索了一下,但没有找到答案。实施起来不会太难还是我错过了什么?

【问题讨论】:

    标签: c++ list stl


    【解决方案1】:

    实际上,绝对没有理由不提供 operator[] 或至少方法 at(int),原因有两个:

    • 它是双链表,因此您需要移动最多 size()/2 个位置的迭代器来获取索引,并且内部保留更多固定迭代器的成本非常低。最后,Qt 库提供了 operator[] 和 at,我没有看到使用它的性能成本。
    • 强迫人们不要使用某些东西是一个非常糟糕的编程习惯,因为列表将有很多可用的容器,如果您在链接访问附近有一个“随机访问”,那么当您需要同时访问时有多种示例,具体取决于哪个运行时点。

    【讨论】:

    • 这纯粹是基于您的意见,还是您创建了一个很好的测试场景,在其中您表明您的 std::list<T>::operator[] 的自定义实现是有效的? (顺便说一句,根据 Stroustrup 的说法,您应该使用的标准容器是 std::vector)。
    【解决方案2】:

    我想我在另一篇 SO 帖子 Extending std::list 中找到了答案

    “你的 operator[] 是 O(N) 时间” - 这个 正是为什么它不包含在 标准的 std::list。 – 迈克尔 伯尔 12 月 14 日 17:29

    不过,这是唯一的原因吗?

    编辑:尽管正如人们所提到的,这似乎更多的是关于性能的一致性问题,而不是严格的性能问题。

    【讨论】:

    • 你的意思是这还不够? :-)
    • 是的。看看别处,.NET LinkedList 没有提供索引器,原因大致相同——它太具有欺骗性了。传统上,当某物具有位置索引器时,假定操作是 O(1)。
    【解决方案3】:

    按索引检索元素是链表的 O(n) 操作,std::list 就是这样。因此决定提供operator[] 具有欺骗性,因为人们会很想主动使用它,然后您会看到如下代码:

     std::list<int> xs;
     for (int i = 0; i < xs.size(); ++i) {
         int x = xs[i];
         ...
     }
    

    这是 O(n^2) - 非常讨厌。所以 ISO C++ 标准特别提到所有支持operator[] 的 STL 序列都应该在摊销的常数时间内完成(23.1.1[lib.sequence.reqmts]/12),这对于vectordeque 是可以实现的,但是不是list

    对于你真正需要这种东西的情况,你可以使用std::advance算法:

    int iter = xs.begin();
    std::advance(iter, i);
    int x = *iter;
    

    【讨论】:

    • 所以基本上,只是为了防止人们犯错?
    • 是的。或者不做出你无法兑现的承诺。在 STL 中,operator[] 承诺 高效 访问任意元素。
    • 请注意,std::list::size() 也可能是 O(n)(参见 stackoverflow.com/questions/228908/is-listsize-really-on/228914),因此即使没有调用,第一个循环也可能是 O(n^2)运算符[]。
    • std::next 是更合适的函数 (std::list&lt; int &gt; list; ...; *std::next(std::begin(list), index) = 1;),因为 it leaves its argument unmodified
    【解决方案4】:

    这不会太难(对于实施者),但在运行时会太难,因为在大多数情况下性能会很糟糕。强制用户浏览每个链接将使那里发生的事情比“myList[102452]”更明显。

    【讨论】:

    • 详细说明位运算符[] 在所有其他使用它的地方都是常数时间运算。为 O(n) 操作赋予相同的名称会不一致且令人困惑。
    • 在地图中,它绝对不是位置索引,这很明显 - 除非地图键是整数,但如果您将位置访问与键查找混淆,那么您已经遇到了更大的问题;)
    • 我知道区别,放心!但它仍然是 operator[] ;)。
    猜你喜欢
    • 2018-08-13
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-02
    • 1970-01-01
    • 2021-01-02
    • 2020-05-03
    相关资源
    最近更新 更多