我发现了很多关于循环不变值以及是否在循环外声明它们的讨论。这不是我所关心的。我关注循环变体值以及明确声明它们是否具有任何潜在的性能影响。
一位同事最近发出了一段代码。让我们说T是一个整数序列,无论是列表,向量等等。
#include <time.h>
#include <algorithm>
template <typename T>
clock_t _check(T &cont, int cnt)
{
clock_t starttime = clock();
srand(27);
while (cnt--)
{
int cur = (rand() << 10) | rand();
cont.insert(std::find_if(cont.begin(), cont.end(), [cur](int i) { return i >= cur; }), cur);
}
return clock() - starttime;
}
当我看到这段代码时,我立刻想到我会在循环时改变
T::iterator it = std::find_if(cont.begin(), cont.end(), [&](int i)
{
return i >= cur;
});
cont.insert(it, cur);
所以基本上,我会通过引用捕获cur,将线分成两部分,以及一些次要的格式差异。就参考而言,我认为没有任何潜在的性能缺点,但如果我错了,请告诉我。迭代器怎么样?我更喜欢这个,因为我认为它更清楚地说明了这个过程,但是我是否意外地做了另一个临时或带走了优化机会?
我知道你要说的是什么,简介并且不要过早地优化。我知道,我相信。问题是我遇到了非常频繁地在循环中声明临时变量的情况,并且变量可能不是迭代器。如果它是指针或某些需要深层复制的数据结构会怎么样?如果函数调用通过引用const与value获取此变量,该怎么办?能够对理论含义有所了解会很好,所以我可以做到这一点并且#34;正确的方式&#34;立即而不是必须一直测试。
那么,在使用临时变量之前明确声明是否有任何缺点?或者编译器是否使这两者完全等效?也许人们喜欢这样的事实:第一个例子是一行而我的是五个?
编辑:我忘了解释为什么我这么想。 &#34; C ++编码标准,101规则,指南和最佳实践&#34; Sutter和Alexandrescu在第9项中说过,#34;减少对象的虚假临时副本并不是一个过早的优化,特别是在内循环中,这样做并不会影响代码的复杂性&#34;。这是他们在谈论的吗?答案 0 :(得分:0)
您的问题的答案是,如果临时变量的复制构造函数很长(例如,复制矩阵或图像)并且无法优化(使用内联),则可能会出现性能损失。
你的第二个例子叫
std::find_if
T::iterator copy constructor
insert
你的第一个例子叫
std::find_if
insert
在您的具体示例中,两者之间的性能差异可能微不足道。但是,您可以创建一个类似的示例,其中图像可能很棒。
答案 1 :(得分:0)
一般来说,对于“足够好”的编译器,您总是可以引入一个命名的局部变量来替换编译器临时性而不会影响性能。
如果您能够通过引入一个命名的局部变量来满足自己,那么您只需要说明编译器将要执行的操作,那么编译器将(应该)生成完全相同的代码。
显然有相关的附带条件。命名的局部变量应具有相同的生命周期,以便它可以保存在寄存器中,而不是强制刷新到内存位置。在某些情况下,允许编译器删除(或内联)某些操作,并且您的替换不应该阻止它这样做。
在这种特殊情况下,我相信迭代器只是指向集合的指针,所以它应该符合这些条件。可能还有其他情况并非如此。
此时我应该请求简洁。一些程序员更喜欢冗长,因为他们认为更多的代码使得阅读更容易。我不赞同这种观点。您的代码应该尽可能短(但不能更短),并且基于这些理由,原始代码远远好于您提议的更改,并且还避免了混淆编译器产生更差代码的风险。