string strLine;//not constant
int index = 0;
while(index < strLine.length()){//strLine is not modified};
strLine.length()
评估多少次
我们是否需要在循环之前使用nLength
withnLength
分配给strLine.length()
string strLine;//not constant
int index = 0;
while(index < strLine.length()){//strLine is not modified};
strLine.length()
评估多少次
我们是否需要在循环之前使用nLength
withnLength
分配给strLine.length()
length
每次您通过循环时都会对其进行评估,但是由于length
是恒定时间O(1)
(如果字符串被更改,则破坏代码)。
length() 在源文件中包含的标头中定义,因此它可以由编译器内联,它的内部调用也可以内联,因此如果编译器能够检测到您的字符串实例在循环中没有更改然后它可以优化对字符串长度的访问,因此它只会被评估一次。无论如何,我认为存储字符串长度的值并不是真正必要的。也许它可以为您节省一些纳秒,但是您的代码会更大,并且当您决定在循环内更改该字符串时会有一些风险。
每次调用它...(每次评估)。如果您不更改字符串长度,则最好使用临时变量,例如:
string strLine;
int stringLength = strLine.length();
int index = 0;
while(index < stringLength);
我认为其中潜伏着第二个问题,那就是“哪个实现更清晰?”
如果从语义上讲,您的意思是 strLine 的长度在循环体内永远不会改变,那么通过分配给一个命名良好的变量来使其显而易见。我什至会把它设为常量。这使其他程序员(和您自己)清楚地知道比较值永远不会改变。
这样做的另一件事是,当您在调试器中单步执行代码时,可以更轻松地查看该值是什么。悬停在本地比在函数调用上的效果要好得多。
说,“把它作为一个函数调用;编译器会优化它”让我觉得过早的悲观。即使 length() 是 O(1),如果没有内联(你不能保证优化没有被禁用),它仍然是一个重要的函数调用。通过使用局部变量,您可以阐明您的含义,并获得可能不平凡的性能优化。
做让你的意图最清楚的事情。
strLine.length() 将被评估 while( i < strLine.length() )
话虽如此,如果字符串是常量,大多数编译器都会对此进行优化(使用适当的设置)。
如果您要使用临时变量,请使用 const 限定符,因此编译器可以添加优化,知道值不会改变:
string strLine;//not constant
int index = 0;
const int strLenght = strLine.Length();
while(index < strLine.length()){//strLine is not modified};
无论如何,编译器本身可能会在访问 Length() 方法时进行这些优化。
编辑:我的组装有点生锈,但我认为评估只进行一次。鉴于此代码:
int main()
{
std::string strLine="hello world";
for (int i=0; i < strLine.length(); ++i)
{
std::cout << strLine[i] <<std::endl;
}
}
生成此程序集:
for (int i=0; i < strLine.length(); ++i)
0040104A cmp dword ptr [esp+20h],esi
0040104E jbe main+86h (401086h)
但是对于这段代码
std::string strLine="hello world";
const int strLength = strLine.length();
for (int i=0; i < strLength ; ++i)
{
std::cout << strLine[i] <<std::endl;
}
生成这个:
for (int i=0; i < strLength ; ++i)
0040104F cmp edi,esi
00401051 jle main+87h (401087h)
如果不使用 const 限定符,则会生成相同的程序集,因此在这种情况下它没有区别。
尝试使用 VSC++ 2005
如前所述,由于该string::length
函数可能完全在标头中定义,并且要求为 O(1),因此几乎可以肯定会评估为简单的成员访问,并内联到您的代码中。由于您没有将字符串声明为易失性,因此允许编译器想象没有外部代码会更改它,并优化对单个内存访问的调用并将值留在寄存器中,如果它发现这是一个好主意。
通过自己获取和缓存值,您增加了编译器能够做同样事情的机会。在许多情况下,编译器甚至不会生成将字符串长度写入堆栈的代码,而只是将其留在寄存器中。当然,如果您调用编译器无法内联的不同函数,则必须将值写入堆栈以防止函数调用占用寄存器。
既然你没有改变字符串,你不应该使用
const string strLine;
只是,因为那时编译器会获得更多关于什么可以改变和什么不能改变的信息——但不确定 C++ 编译器究竟能变得多么聪明。
strLine.length()
每次您绕过循环时都会对其进行评估。
你是对的,因为它使用起来会更有效nLength
,特别是如果strLine
很长。