Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Isn';t呼叫列表<;T>;::end()`低效? 在C++程序设计书中,我看到了下面的代码 STD::列表< /C>迭代器:< /P> for (iterator = list.start(); iterator != list.end(); iterator++)_C++_Iterator - Fatal编程技术网

Isn';t呼叫列表<;T>;::end()`低效? 在C++程序设计书中,我看到了下面的代码 STD::列表< /C>迭代器:< /P> for (iterator = list.start(); iterator != list.end(); iterator++)

Isn';t呼叫列表<;T>;::end()`低效? 在C++程序设计书中,我看到了下面的代码 STD::列表< /C>迭代器:< /P> for (iterator = list.start(); iterator != list.end(); iterator++),c++,iterator,C++,Iterator,一直调用list.end()不是效率低下吗?是否将保存到另一个变量更好,还是C++编译器(即G++)自动处理这个问题?< /P> < P> >代码>清单::()/代码>应该具有恒定的时间复杂性,特别是对于链表,这意味着它可能是非常有效的。 如果您的算法允许的话,存储值可能会稍微高效一些(同样,对于特别是链表,差异不大) 哦,而且一定要阅读Steve Jessop关于自己测试效率的回答 实际上,对于STL容器,container::end()非常便宜。事实上,C++标准强>任务> 算法的复杂性,对

一直调用
list.end()
不是效率低下吗?是否将保存到另一个变量更好,还是C++编译器(即G++)自动处理这个问题?< /P> < P> >代码>清单::()/代码>应该具有恒定的时间复杂性,特别是对于链表,这意味着它可能是非常有效的。 如果您的算法允许的话,存储值可能会稍微高效一些(同样,对于特别是链表,差异不大)


哦,而且一定要阅读Steve Jessop关于自己测试效率的回答

实际上,对于STL容器,
container::end()
非常便宜。事实上,C++标准<>强>任务> <强>算法的复杂性,对于几种类型的方法(如果不是全部),和总是恒定的时间。 此外,编译器可以自由地内联这些方法,基本上消除了可能产生的任何开销。除了存储列表外,我想不出任何其他方法可以在固定时间内获取列表的结尾,因此您的
list.end()
调用可能最终成为字段访问,这在x86平台上并不比存储在堆栈上更昂贵


您的里程数可能因其他系列而异,但可以肯定的是,
list.end()
最终不会成为您的瓶颈。

这不太可能有什么不同

标准容器函数是内联的,因此应该没有明显的函数调用开销。剩下的问题是优化器是否足够聪明,以避免不必要的开销,而这些开销对于执行比较来说并不是绝对必要的。例如:它实际上是否创建了一个临时的
list::iterator
对象,填写其当前位置字段,然后将该字段读回,或者比较结果是否只是
iterator
中的值与列表头中的值之间的指针比较

即使有一些不必要的开销,与增加迭代器相比,它可能可以忽略不计,与循环体相比,它甚至可以忽略不计


你可以测试它,这比猜测更可靠。记住启用优化——在没有优化的情况下测试性能有点像说,如果Blake从预热跑道走到公共汽车上的速度更快,Blake必须比Bolt快。

一般来说,不,这不是低效的
end()
通常是一个内联函数,编译器将生成好的代码来执行它所做的任何操作。更重要的是,与什么相比效率低下?是的,您可以添加代码来创建一个变量来保存结果,这可能比简单地调用
end()
要快一点,也可能不会快一点。这样的改变似乎不太可能产生足够大的速度差异,从而将太慢的程序转变为满足要求的程序。

如果需要微优化,可以

一般来说,调用
list.end()
不会对性能造成严重影响,也可能不会造成问题。它可能在每次调用时返回相同的值,也可能是内联的,等等。虽然速度不慢,但确实需要一些时间

如果您确实需要速度,您希望使用
for(迭代器=list.start(),end=list.end;iteration!=end;++iterator)
。这将缓存结束迭代器(并进行预inc),并且不应重复调用


第二种类型通常是不必要的,但是如果
.end()
很昂贵或者循环非常大,则可能会很有用。

调用
std::list::end()
不太可能是一个大的效率问题,可能只是读取一个值。但是,您可以通过将编译器存储为变量来提示它不打算更改。对于其他容器,除了读取稍微复杂一点的基址之外,还可能涉及计算。仍然没有什么戏剧性的,但可能值得避免


但是,请注意,它也可能会更改循环的语义:如果循环的主体可以附加元素,则前端可能会移动。有趣的是,我在标准中没有发现任何特定的要求,说明在将元素插入容器时,
std::list::end()
是否会发生变化(我可以想象实现在哪些地方会发生变化,而在哪些地方不会发生变化;不过,很可能不会发生变化)。如果您想在修改列表时获得有保证的行为,您可以在每次迭代中调用
list.end()


顺便说一句,关于使用
iterator++
而不是
++iterator
,我有一个更大的性能问题,尤其是作者在书中使用的。尽管如此,这是一种微观优化,就像存储list.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
是双端链表的末尾,因此它应该是一个常量时间操作。给定y