像PHP这样的脚本语言有这样的for循环会是一个非常糟糕的主意:
string s("ABCDEFG");
int i;
for( i = 0; i < s.length(); i ++ )
{
cout << s[ i ];
}
这是一个例子,我没有建立这样的程序。 (对于那些觉得他们必须告诉我为什么这段代码&lt; 在这里插入不好的东西的人&gt;)
如果将此C ++示例转换为类似的PHP脚本,则会在每个循环周期中计算字符串的长度。这会在现实脚本中造成巨大的性能损失。
我认为这同样适用于C ++程序但是当我看一下教程,几个开源库和其他代码时,我发现循环的限制器没有预先计算。
s
的长度吗?答案 0 :(得分:11)
这都是相对的。
PHP被解释,但如果s.length
落入PHP解释器的编译部分,它将不会很慢。但即使它很慢,s[i]
花费的时间又会怎样,cout <<
花费的时间呢?
在淹没其他东西的同时,很容易专注于循环开销。
就像你用C ++写的那样,并且cout
正在写入控制台,你知道什么会占主导地位吗? cout
会远远地,因为那个看上去无辜的<<
运算符会调用大量的库代码和系统例程。
答案 1 :(得分:4)
你应该学会证明更简单的代码。试着说服自己,迟早你会将string :: length实现替换为更优化的实现。 (即使你的项目很可能会错过所有截止日期,并且优化字符串::长度将是你问题中最少的。)这种思维将帮助你专注于真正重要的事情,即使它并不总是那么容易......
答案 2 :(得分:3)
这取决于string
的实施方式。
在null终止字符串时,您必须在每次迭代时计算大小。
std::string
是一个容器,在<(1)时间内应返回
它取决于(再次)实现。
答案 3 :(得分:2)
如果他能够确定其值不会改变,那么优化器确实可以优化对length
的调用 - 然而,如果你预先计算它,你就是安全的(在许多情况下)但是,优化是不可能的,因为编译器不清楚条件变量是否可以在循环期间改变)。
在许多情况下,它并不重要,因为所讨论的循环与性能无关。与for(int i=0; i < somewhat(); ++i)
相比,使用经典for(int i=0,end=somewhat(); i < end; ++i
输入的工作量更少,更易于阅读。
请注意,C ++编译器通常会内联小函数,例如length
(通常会从字符串对象中检索预先计算的长度)。解释的脚本语言通常需要对函数调用进行字典查找,因此对于C ++,每次循环迭代一次冗余校验的相对高估可能要小得多。
答案 4 :(得分:2)
我不知道php
,但我可以告诉c++
做什么。
考虑:
std::string s("Rajendra");
for (unsigned int i = 0; i < s.length(); i++)
{
std::cout << s[i] << std::endl;
}
如果您要查找length()
的定义(右键单击length()
并单击“转到定义”)或者如果您使用的是Visual Assist X,则将光标放在{{1然后按length()
,您会看到以下内容:
Alt+G
其中size_type __CLR_OR_THIS_CALL length() const
{ // return length of sequence
return (_Mysize);
}
的类型为_Mysize
,这清楚地表明字符串的长度已预先计算,并且每次调用int
时仅返回存储的值。
然而,IMPO(在我个人看来),这种编码风格很糟糕,应该最好避免。我更愿意关注:
length()
这样,您将节省调用std::string s("Rajendra");
int len = s.length();
for (unsigned int i = 0; i < len; i++)
{
std::cout << s[i] << std::endl;
}
函数的开销等于字符串次数的长度,这样可以节省堆栈帧的推送和弹出。当你的弦很大时,这可能非常昂贵
希望有所帮助。
答案 5 :(得分:1)
答案 6 :(得分:1)
你是对的,通常会在每次循环迭代时评估s.length()
。你最好写作:
size_t len = s.length();
for (size_t i = 0; i < len; ++i) {
...
}
而不是上述。也就是说,对于只有几次迭代的循环,调用length()的频率并不重要。
答案 7 :(得分:1)
简短回答,因为在某些情况下,您希望每次调用它。
其他人的解释:http://bytes.com/topic/c/answers/212351-loop-condition-evaluation
答案 8 :(得分:0)
嗯 - 因为这是一种非常常见的情况,大多数编译器都会预先计算价值。特别是在循环遍历数组和非常常见的类型时 - 字符串可能就是其中之一。
此外,引入一个额外的变量可能会破坏其他一些循环优化 - 它实际上取决于您使用的编译器,并且可能会从版本更改为版本。
因此,在某些情况下,“优化”可能会适得其反。
如果代码是非真实的“热点”,其中每个性能滴答都很重要,你应该像你一样写:没有“手动”预先计算。
在编写代码时,可读性也非常重要!
只有经过深入分析后才能非常仔细地进行优化!
答案 9 :(得分:0)
std::string.length()
返回存储在容器中的固定变量。它已经预先计算了
答案 10 :(得分:0)
只有在 知道 时,您才能预先计算字符串的长度。字符串在循环内不会发生变化。
我不知道为什么在教程中这样做。一些猜测:
1)为了让你养成习惯,这样当你改变循环中字符串的值时你就不会受到冲击
2)因为它更容易理解。
是的,如果优化器可以确定字符串是否不会改变
,那么优化器会尝试改进这一点答案 11 :(得分:0)
编译器可能能够保存调用的结果并优化掉所有额外的函数调用,但它可能不会。但是,函数调用的成本将非常低,因为它所要做的就是返回一个int。最重要的是,它很有可能被内联,完全消除了函数调用的成本。
但是,如果您真的在意,您应该对代码进行分析,看看预先计算该值是否会使其更快。但是,无论如何只选择预先计算它也不会有什么坏处。它不会花费你任何东西。但在大多数情况下,赔率并不重要。有一些容器 - 比如列表 - 其中size()可能不是O(1)操作,然后预先计算将是真正的好主意,但对于大多数它可能并不重要 - 特别是如果你的循环内容足以压倒这种高效函数调用的成本。对于std :: string,它应该是O(1),并且可能可以被优化掉,但你必须进行测试以确保 - 当然还有你编译的优化级别之类的东西at会改变结果。
预先计算更安全,但通常没有必要。
答案 12 :(得分:0)
在这种特殊情况下,std::string.length()
通常(但不是necessarily)常量操作,通常效率很高。
对于一般情况,循环终止条件可以是任何表达式,而不仅仅是循环索引变量的比较(实际上,C / C ++不识别任何特定索引,只是初始化表达式,循环测试表达式和循环计数器表达式(每次都执行它).C / C ++ for循环基本上是do/while
复合语句的语法糖。
答案 13 :(得分:0)
std::sting::length()
返回预先计算的值。每次调用方法size()
时,其他stl容器会重新计算其大小
例如
std::list::size()
重新计算尺寸和std::vector::size()
返回一个
预先计算的值这取决于如何实现容器的内部存储。
std::vector
是一个容量为2 ^ n的数组,std::list
是一个链接列表。
答案 14 :(得分:0)
只是为了获取信息,在我的计算机上,g ++ 4.4.2,使用-O3,使用给定的代码片段,函数std::string::length() const
被调用8次。
我同意这是预先计算的,并且该功能很可能被内联。知道何时使用自己的函数/类仍然非常有趣。
答案 15 :(得分:0)