延迟声明变量是否更有效?

Is it more efficient to declare variables late?

本文关键字:有效 是否 声明 变量 延迟      更新时间:2023-10-16

延迟声明变量是否会增加内存或可能提高计算效率?

的例子:

int x;
code
..
.
.
. x is able to be used in all this code
.
actually used here
.
end

code
..
.
.
.
int x;
actually used here
.
end

谢谢。

写逻辑上最有意义的东西(通常更接近使用)。编译器能够并且将会发现这样的事情,并生成最适合您的目标体系结构的代码。

您的时间远比尝试猜测编译器和处理器上的缓存的交互更有价值。


例如在x86上:

#include <iostream>
int main() {
  for (int j = 0; j < 1000; ++j) {
    std::cout << j << std::endl;
  }
  int i = 999;
  std::cout << i << std::endl;
}
:相比

#include <iostream>
int main() {
  int i = 999;
  for (int j = 0; j < 1000; ++j) {
    std::cout << j << std::endl;
  }
  std::cout << i << std::endl;
}
编制:

g++ -Wall -Wextra -O4 -S measure.c
g++ -Wall -Wextra -O4 -S measure2.c

diff measure*.s检测输出时给出:

<       .file   "measure2.cc"
---
>       .file   "measure.cc"
甚至

:

#include <iostream>
namespace {
  struct foo {
    foo() { }
    ~foo() { }
  };
}
std::ostream& operator<<(std::ostream& out, const foo&) {
  return out << "foo";
}
int main() {
  for (int j = 0; j < 1000; ++j) {
    std::cout << j << std::endl;
  }
  foo i;
  std::cout << i << std::endl;
}

#include <iostream>
namespace {
  struct foo {
    foo() { }
    ~foo() { }
  };
}
std::ostream& operator<<(std::ostream& out, const foo&) {
  return out << "foo";
}
int main() {
  foo i;
  for (int j = 0; j < 1000; ++j) {
    std::cout << j << std::endl;
  }
  std::cout << i << std::endl;
}

g++ -S生成的程序集的diff的结果除了文件名之外仍然是相同的,因为没有副作用。如果有副作用,那么这将决定你在哪里构建对象——你希望副作用在什么时候发生?

对于基本类型,如int,从性能的角度来看,这无关紧要。对于class类型,变量定义还包括构造函数调用,如果控制流跳过该变量,则可以提交构造函数调用。此外,对于基本类型和class类型,定义至少应该延迟到有足够的信息使这种变量有意义的时候。对于非默认的可构造类类型,这是强制性的;对于其他类型,它可能不是,但它迫使您使用未初始化的状态(如-1或其他无效值)。你应该尽可能晚地定义变量,在尽可能小的范围内;从性能的角度来看,这可能并不重要,但从设计的角度来看,这总是很重要的。

一般来说,应该声明在何时何地使用这些变量。它提高了可靠性、可维护性,并且出于纯粹实用的原因,提高了内存局域性。

即使你有一个大对象,并且你在循环体外部或内部声明它,唯一的区别是构造和赋值;实际的内存分配实际上是相同的,因为当代的分配器非常擅长短期分配。

你甚至可以考虑创建新的,匿名作用域,如果你有一小部分代码的变量是不需要的(尽管这通常表明你最好使用一个单独的函数)。

所以基本上,以最合乎逻辑的方式编写,你通常也会得到最有效的代码;或者至少你不会比在顶部声明所有内容更糟糕。

对于简单类型,这两种方法既不提高内存效率,也不提高计算效率。对于更复杂的类型,在使用它们的地方附近将内容放在缓存中(从构造开始)可能会更有效。它还可以最小化内存剩余分配的时间。