C++ 在循环之外声明参数是否更有效;什么范围?

C++ 在循环之外声明参数是否更有效;什么范围?,c++,optimization,scope,declaration,C++,Optimization,Scope,Declaration,有时,在查看优化的代码时,我会看到仅在循环范围内使用的参数的声明被移到了循环之外 大概是这样的: A arr[BIG_NUMBER]; // .... // for (int i=0; i!=BIG_NUMBER; ++i) { B b = arr[i].getB(); // ... do some work with b. } 变成这样: A arr[BIG_NUMBER]; // .... // B b; for (int i=0; i!=BIG_NUMBER; +

有时,在查看优化的代码时,我会看到仅在循环范围内使用的参数的声明被移到了循环之外

大概是这样的:

A arr[BIG_NUMBER];

// .... //

for (int i=0; i!=BIG_NUMBER; ++i)
{
    B b = arr[i].getB();
    // ... do some work with b.
}
变成这样:

A arr[BIG_NUMBER];

// .... //

B b;
for (int i=0; i!=BIG_NUMBER; ++i)
{
    b = arr[i].getB();
    // ... do some work with b.
}
大概原因是我们在不断地重新定义
b
。但这样做合理吗?答案是否因B是基元类型还是类而不同

我认为,虽然for循环中变量的范围限制可能会阻止它们在循环之外被访问,但由于循环的内容存在于同一堆栈框架中,“实际”声明只发生一次

(NB,我已经考虑过了,但是考虑到这是一个不同的问题,因为它与声明相关而不是初始化有关的任何费用)。


编辑-改进的标题

如果是原语类型,编译器将相应地进行优化

如果它是用户定义的类,则取决于。什么更昂贵,一个额外的初始化或
BIG_NUMBER
析构函数

比较这些:

B b;  //one initialization
for (int i=0; i!=BIG_NUMBER; ++i)
{
    b = arr[i].getB();  //BIG_NUMBER assignments
}

for (int i=0; i!=BIG_NUMBER; ++i)
{
    B b = arr[i].getB();  //BIG_NUMBER initializations 
                          //should be the same as an assignment
} //BIG_NUMBER objects destroyed

没有一般的答案。这取决于编译器B的类型 您正在使用,并且可能在循环中正在做什么(在 分配)。你所能做的就是测量,即使这样也只能说明问题
您可以了解在一台特定机器上运行的特定编译器

@JoachimPileborg构造函数/析构函数是否昂贵并不重要。编译器还可以选择调整块入口/出口上的堆栈指针(不记得是否可以要求g++这样做,默认情况下不会),尽管与循环构造相比,成本微不足道。注意:额外的作用域可以通过用另一对花括号将所有内容包装起来来抵消<代码>{B;for(…){}是一个可接受的构造,通常用于RAII构造。当对象拥有一些昂贵的构造资源时,它会产生影响,而这些资源不受赋值的影响(因此您应该在循环外进行初始化)。或者当
getB
按值返回时,您会得到一个副本省略,这当然是赋值不可能的(因此您应该在循环内初始化,或者交换而不是赋值)。移动语义主要缓解了后者。