C++ 在可能的情况下,是否应避免循环的范围?
在我的DirectX程序中,我编写了一个循环,循环通过std::string,然后运行性能分析器,并意识到这个循环消耗了大量的cpu时间。更重要的是,当我运行我的程序时,我有大约1300 FPS。所以我决定用这个做点什么,我把基于范围的循环改为典型的迭代。我是说我改变了:C++ 在可能的情况下,是否应避免循环的范围?,c++,c++11,C++,C++11,在我的DirectX程序中,我编写了一个循环,循环通过std::string,然后运行性能分析器,并意识到这个循环消耗了大量的cpu时间。更重要的是,当我运行我的程序时,我有大约1300 FPS。所以我决定用这个做点什么,我把基于范围的循环改为典型的迭代。我是说我改变了: for( char c : std_string_name ) 到 (大小i=0;i(从注释中移动) 基于范围的循环使用迭代器,由于额外的调试检查,VC++迭代器在调试模式下往往速度较慢;一旦在发布模式下,它们应该归结为指针
for( char c : std_string_name )
到
(大小i=0;i(从注释中移动)
基于范围的循环使用迭代器,由于额外的调试检查,VC++迭代器在调试模式下往往速度较慢;一旦在发布模式下,它们应该归结为指针,因此应该没有性能差异
此外,您的测试没有意义,因为:
- 这样的空循环可能会被优化器优化掉,因此您只能在未优化的构建中可靠地运行测试——但在未优化的构建中,测试性能是没有意义的
- 您只按特定顺序运行每个测试一次-这可能会给出误导性信息,例如,由于第一个循环中的缓存“预热”(尽管我不认为是这种情况,因为
str
刚刚被访问以进行构建);为了获得有统计意义的信息,你必须以随机顺序重复测试多次
我用你的代码写了以下内容:
#include <iostream>
#include <string>
#include <ctime>
int iter1( std::string str ){
int sum = 0;
for( char c : str ){
sum += c;
}
return sum;
}
int iter2( std::string str ){
int sum = 0;
for( char &c : str ){
sum += c;
}
return sum;
}
int iter3( std::string str ){
int sum = 0;
std::string::size_type len = str.length();
for( size_t i=0;i<len;++i){
char c = str[i];
sum += c;
}
return sum;
}
int main(){
std::string str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for(int i=0;i<22;++i)
str += str;
clock_t a, b, c;
clock_t aa, bb, cc;
int sum = 0;
a=clock();
sum += iter1(str);
aa = clock() -a ;
b=clock();
sum += iter2(str);
bb=clock()-b;
c=clock();
sum += iter3(str);
cc=clock()-c;
std::cout << "aa=" << aa << " bb=" << bb << " cc=" << cc << " sum=" << sum << std::endl;
}
#包括
#包括
#包括
int iter1(std::string str){
整数和=0;
for(字符c:str){
总和+=c;
}
回报金额;
}
int iter2(std::string str){
整数和=0;
用于(字符和字符:str){
总和+=c;
}
回报金额;
}
int iter3(std::string str){
整数和=0;
std::string::size_type len=str.length();
对于(size_t i=0;i您是在调试模式还是发布模式下编译的?基于范围的循环使用迭代器,而VC++迭代器在调试模式下由于额外的调试检查往往速度较慢;一旦在发布模式下,它们应该归结为指针,因此性能应该没有差异。不要粘贴代码图像,在问题中编写代码您忘记了变量ant:for(const char&c:std_string_name){…}
MSVS 2012必须有一个调试器。为什么不比较不同情况下的实际反汇编?main
需要返回int
。可能是基于范围的循环在检查std::string是否有更多元素时为每个迭代创建结束迭代器?此外,我在发布模式下测试了我的应用程序,现在我看不出有什么不同@MichalW:不,实际上,基于范围的循环的主要兴趣之一是它确保缓存end
迭代器;尽管结果是修改循环中的迭代容器会导致未定义的行为。请注意,调试生成中的MSVC迭代器性能可以通过_迭代器_DEBU大大提高G_LEVEL#define。请看哇!谢谢!这个答案非常有用!当然应该注意,不同的编译器可能会有所不同,但并非所有基于范围的循环总是比基于迭代器的循环慢。还要注意,我确保循环做了一些事情(在本例中,计算校验和),就像空循环一样如果编译器足够聪明,“消失”。第三个变量速度最慢的原因是libstdc++的std::string
是写时复制(这在C++11中是非法的,但他们保留它是为了ABI稳定性),因此它必须在每个可变访问上取消共享,就像非常量操作符[]
在这里使用。当它们更改为一个正常的实现时,就像在MSVC中使用的一个类似的实现(使用SSO的非CoW),如果三者之间有任何有意义的区别,我会感到惊讶。
void main(){
for(int i=0;i<10;++i)
str += str;
clock_t a, b, c;
clock_t aa, bb, cc;
a=clock();
iter1(str);
aa = clock() -a ;
b=clock();
iter2(str);
bb=clock()-b;
c=clock();
iter3(str);
cc=clock()-c;
}
void iter1( std::string str ){
for( char c : str ){
}
}
void iter2( std::string str ){
for( char &c : str ){
}
}
void iter3( std::string str ){
for( size_t i=0;i<str.length();++i){
char c = str[i];
}
}
#include <iostream>
#include <string>
#include <ctime>
int iter1( std::string str ){
int sum = 0;
for( char c : str ){
sum += c;
}
return sum;
}
int iter2( std::string str ){
int sum = 0;
for( char &c : str ){
sum += c;
}
return sum;
}
int iter3( std::string str ){
int sum = 0;
std::string::size_type len = str.length();
for( size_t i=0;i<len;++i){
char c = str[i];
sum += c;
}
return sum;
}
int main(){
std::string str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for(int i=0;i<22;++i)
str += str;
clock_t a, b, c;
clock_t aa, bb, cc;
int sum = 0;
a=clock();
sum += iter1(str);
aa = clock() -a ;
b=clock();
sum += iter2(str);
bb=clock()-b;
c=clock();
sum += iter3(str);
cc=clock()-c;
std::cout << "aa=" << aa << " bb=" << bb << " cc=" << cc << " sum=" << sum << std::endl;
}