在循环中创建一个对象

时间:2010-06-09 20:05:43

标签: c++ optimization

 std::vector<double> C(4);
 for(int i = 0; i < 1000;++i)
  for(int j = 0; j < 2000; ++j)
  {   
   C[0] = 1.0;
   C[1] = 1.0;
   C[2] = 1.0;
   C[3] = 1.0;
  }

更快
 for(int i = 0; i < 1000;++i)
  for(int j = 0; j < 2000; ++j)
  {
   std::vector<double> C(4);
   C[0] = 1.0;
   C[1] = 1.0;
   C[2] = 1.0;
   C[3] = 1.0;
  }

我意识到这种情况发生是因为std::vector在循环中被反复创建和实例化,但我认为这将是优化

是否完全错误是否尽可能将变量保持在循环中?我(这可能是错误的)印象是这将为编译器提供优化机会。

或许这只适用于POD类型,而不适用于std::vector

编辑:我在Windows XP上使用了VC ++ 2005(发布模式)并进行了全面优化(/Ox

7 个答案:

答案 0 :(得分:3)

  

尽可能将变量保持在循环中是完全错误的吗?我(这可能是错误的)印象是这将为编译器提供优化机会。

不,这是一个很好的经验法则。但这只是一个经验法则。 最小化变量的范围使编译器可以更自由地进行寄存器分配和其他优化,至少同样重要的是,它通常会产生更易读的代码。但它也取决于重复的创造/破坏是否便宜,或完全被优化。通常情况就是如此......但并非总是如此。

正如您所发现的,有时这是一个坏主意。

答案 1 :(得分:2)

问题是堆活动。将std::vector<double> C(4);替换为std::array<double, 4> C;,它不再对您放置变量的位置产生任何影响。

答案 2 :(得分:2)

  

我的印象是(这可能是假的)这会为编译器提供优化机会。

对于内置类型(如int或double),这可能是正确的。

这里的问题是你正在使用vector,它需要在进入循环体时运行构造函数,并在离开时使用析构函数。由于这两种方法都是非平凡的,因此编译器无法优化这些方法,因为您的程序将不再正确。

作为对此的反例,想象一下如果使用文件对象而不是向量,这样的优化会做什么。

答案 3 :(得分:1)

第二种方式是分配新内存(在你的情况下为1000 * 2000次)。每一个都是堆中的全新内存位置(虽然并不总是新的,但可以位于同一位置)。内存分配比仅修改已分配内存中包含的值需要更长的时间。

第一种方法是分配1个内存位置数组,只修改其中的值。 如果编译器为此做了优化(情况并非总是这样),最好不要将它留给编译器,如果你可以选择自己作为程序员分配更少的内存(或更少)。

答案 4 :(得分:1)

在这种情况下,vector的创建很昂贵,因为它可能会在堆上分配一个大小为4的数组。

如果你事先知道'本地'矢量的大小,你也可以使用自动数组

for( int i = 0; i != 2000; ++i ) {
   int C[4]; // no initialization
   C[0] = 1;
   // ...
}

这样就省去了分配空闲内存的成本。

答案 5 :(得分:0)

obj的范围将在循环内部,因此一旦循环完成,您将无法使用它。此外,对于实例化的对象,然后随着循环(go)的进行多次销毁。最后,除了浪费时间构建然后摧毁物体外,什么都没有完成。

答案 6 :(得分:0)

首先要做的是确保设计正常,这意味着:

  • 代码是否易于理解
  • 代码是否可以防止错误
  • 代码是否易于扩展

我认为在这种情况下,它确实意味着在循环中定义变量会更好。

只有当您遇到真正的性能问题时,才可以优化您的代码(如果编译器还没有为您执行此操作),例如将变量声明放在循环之外。