调用"list<T>::end()"不是效率低下吗?
Isn't calling `list<T>::end()` inefficient?
在一本C++编程书中,我看到了std::list
迭代器的以下内容:
for (iterator = list.start(); iterator != list.end(); iterator++)
一直打电话给list.end()
不是效率低下吗?将结尾保存到另一个变量会更好,还是C++编译器(即 g++(会自动处理这个问题?
list::end()
应该具有恒定的时间复杂度,特别是对于链表,这意味着它可能非常有效。
如果您的算法允许,存储值可能会稍微高效一些(同样,对于特别链表,差异不太可能很大(。
哦,请阅读史蒂夫杰索普关于自己测试效率的答案!
调用std::list<T>::end()
不太可能是一个大的效率问题,可能只读取单个值。但是,您会给编译器一个提示,表明它不会通过将它存储为变量来更改。对于其他容器,除了读取基址之外,还可能涉及计算,这更复杂一些。仍然没有什么戏剧性的,但可能值得避免。
但请注意,它也可能改变循环的语义:如果循环的主体可能附加元素,则前一端可能会移动。有趣的是,我在标准中没有找到任何具体要求,说明在将元素插入容器时std::list<T>::end()
是否会更改(我可以想象它确实会更改的实现以及一些不会更改的实现;很可能它不会更改,不过(。如果要在修改列表时获得有保证的行为,则很可能在每次迭代中调用list.end()
。
顺便说一句,我有一个更大的性能问题,那就是使用iterator++
而不是++iterator
,尤其是这是作者在书中使用的。尽管如此,这是一个微优化,就像存储list.end()
的结果一样,但做起来很便宜。
一般来说,不,它不是低效的。 end()
通常是一个内联函数,编译器将生成良好的代码来执行它所做的任何事情。更重要的是,与什么相比效率低下?是的,您可以添加代码来创建变量来保存结果,这可能比简单地调用 end()
快一点,也可能不会快一点。这样的变化似乎不太可能产生足够大的速度差异,将太慢的程序变成满足要求的程序。
这不太可能有任何区别。
标准容器函数是内联的,因此应该没有明显的函数调用开销。剩下的就是优化器是否足够聪明,以避免不必要的开销,而这些开销对于执行比较并不是绝对必要的。例如:它是否实际上创建了一个临时list::iterator
对象,填写其当前位置字段,然后读回该字段,或者比较最终只是作为iterator
中的值与列表头部的值之间的指针比较?
即使有一些不必要的开销,与增加迭代器相比,它也可能可以忽略不计,与循环体相比甚至可以忽略不计。
你可以测试它,这比猜测更可靠。记住要启用优化——在没有优化的情况下测试性能有点像说,如果布莱克从热身跑道到公共汽车走得更快,布莱克一定比博尔特快。
实际上,对于 STL 容器,container::end()
非常便宜。事实上,C++标准要求多个类的几种方法(如果不是全部(的算法复杂性,并且container::end()
始终是恒定时间。
此外,编译器可以自由地内联这些方法,基本上消除了它可能具有的任何开销。我想不出除了存储列表之外,没有其他方法可以在恒定时间内获取列表的末尾,因此您的list.end()
调用可能最终成为字段访问,这在 x86 平台上并不比将其存储在堆栈上更昂贵。
您的里程可能因其他系列而异,但可以肯定的是,list.end()
最终不会成为您的瓶颈。
如果您需要微优化,是的。
一般来说,呼叫list.end()
不会对性能造成重大影响,也可能不会成为问题。它可能每次调用都返回相同的值,可以内联,等等。虽然不慢,但确实需要一些小时间。
如果你绝对需要速度,你想使用for (iterator = list.start(), end = list.end; iteration != end; ++iterator)
.这会缓存结束迭代器(并执行预 inc(,并且不应有重复调用。
第二种类型通常是不必要的,但如果.end()
昂贵或循环非常大,则可能很有用。
虽然过早的优化是邪恶的,但好习惯不是。如果您不希望循环终止条件发生变化,即您没有更改容器,则可以使用此模式:
for (mylist::iterator it = alist.begin(), finish = alist.end(); it != finish; ++it)
如果编译器无法确定容器未更改,则不太可能为你进行此优化。
请注意,这不太可能产生可测量的时间差异,但不会造成伤害。
不std::list
上缓存end()
的一个很好的理由是它可以防止您犯以下错误:
for (iterator = list.rstart(), end = list.rend(); iterator != end; iterator++) {
// modify list
当您在 std::list
中进行修改时,任何迭代器都不会失效,但rend
不是哨兵(它指向底层列表的第一个元素(,这意味着如果您附加到反向列表的末尾(也称为附加到未反向列表的开头(,它将不再是列表的末尾。
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 为什么当我解模块化时,这个C++代代码"效率较低"?
- 代码的效率. 转到和函数调用
- 对于循环C++可能效率低下
- 反转依赖于 end() 的迭代器
- std::multimap<std::chrono::milliseconds, T>::rbegin 在 MSVS-13 中指向 end()?
- 在C++中使用 Catch 测试框架编译错误"error: expected ';' at end of declaration list"
- 内存效率表示最短路径的方法?
- 如何提高该函数的运行效率?
- 效率:标准::数组与标准::矢量
- 如何提高BST的搜索操作效率?
- remove(str.begin(), str.end(), );无法正常工作(我正在使用视觉工作室 2012)
- 在 ifcondition al中 find() C++ STL 中的 == a.end() 有什么用?
- 野牛/yacc 解析器在不被空格分隔时跳过 grammer - "unexpected $end"
- "错误 C0000:语法错误,令牌"<EOF>"处出现意外$end,并且不确定
- 了解向量中的 .begin 和 .end
- 字符串引用参数的效率C++
- 如何实现链表的 end()?
- 调用"list<T>::end()"不是效率低下吗?