变量定义是否超出优化范围?
Is variable defined out of scope Optimized?
因此,有些人可能同意(代码 1):
void func()
{
int a, b;
{
//Do something with a and b
}
}
看起来比(代码 2)更好(或者是更好的做法):
void func()
{
int a;
{
int b;
//Do something with a and b
}
}
此外,比这个(代码 3):
void func()
{
{
int a, b;
//Do something with a and b
}
}
如果没有 a
或 b
的重新声明,这些代码是否等效?编译器会优化这个吗?
对于普通类型(这具有技术意义),它们的 destruction/creation 只是指示编译器保证不需要知道它们的值是什么。优化时可以“忽略”变量消失后任何可能的悬空引用或指针。
因此,在将要使用的最小范围内创建数据有时会导致编译器生成更优化的代码。如果“某物”是一个函数,编译器看不到它的细节,它通过引用(或指针)获取一个整数,编译器不知道它需要在实际内存中保留该实际整数多长时间。但是(由程序员)保证在范围结束后,它不需要实际内存中的实际整数。
除非是那种情况,否则没有区别。当您要求时,编译器不必实际创建 int
类型的对象;但有时他们会被其他要求所迫。
在调试版本中,编译器会在您要求的地方创建变量,并在您要求时清理它们,因为这样可以更轻松地单步执行代码和检查程序状态。
对于非平凡类型(基本上,具有 vtable 的对象,或具有构造函数的对象,或具有析构函数的对象,或在递归定义中包含非平凡类型的对象),对象 creation/destruction 可以具有可见的副作用,因此何时发生可能很重要。编译器仍然可以在 as-if 规则下移动它们(即,程序集只需要像你写的那样运行),所以如果它能证明那些非平凡的 construction/destruction 操作不关心它们何时 运行(在标准形式意义上)它们可以被编译器移动。
在你的示例代码中是等效的,因为你使用了简单的类型,比如 int
。但一般来说,如果您将使用对象,这可能是错误的。
考虑以下示例:
void func()
{
SomeObj a, b;
SomeOtherObj c;
{
//Do something with a and b
}
}
在这种情况下,对象 a
和 b
不能在 c
之前被删除,因为对象总是以创建的相反顺序被删除。尽管从理论上讲,如果没有可观察到的副作用,一些编译器可能会在 c
之后重新安排 a
和 b
的创建,并在函数结束之前将其删除。
第二种情况
void func()
{
SomeObj a;
SomeOtherObj c;
{
SomeObj b;
//Do something with a and b
}
}
b
将在作用域关闭后立即删除,但 a
的行为与第一种情况相同。
对于第三种情况,a
的行为与第二种情况下的 b
相同。
因此,有些人可能同意(代码 1):
void func()
{
int a, b;
{
//Do something with a and b
}
}
看起来比(代码 2)更好(或者是更好的做法):
void func()
{
int a;
{
int b;
//Do something with a and b
}
}
此外,比这个(代码 3):
void func()
{
{
int a, b;
//Do something with a and b
}
}
如果没有 a
或 b
的重新声明,这些代码是否等效?编译器会优化这个吗?
对于普通类型(这具有技术意义),它们的 destruction/creation 只是指示编译器保证不需要知道它们的值是什么。优化时可以“忽略”变量消失后任何可能的悬空引用或指针。
因此,在将要使用的最小范围内创建数据有时会导致编译器生成更优化的代码。如果“某物”是一个函数,编译器看不到它的细节,它通过引用(或指针)获取一个整数,编译器不知道它需要在实际内存中保留该实际整数多长时间。但是(由程序员)保证在范围结束后,它不需要实际内存中的实际整数。
除非是那种情况,否则没有区别。当您要求时,编译器不必实际创建 int
类型的对象;但有时他们会被其他要求所迫。
在调试版本中,编译器会在您要求的地方创建变量,并在您要求时清理它们,因为这样可以更轻松地单步执行代码和检查程序状态。
对于非平凡类型(基本上,具有 vtable 的对象,或具有构造函数的对象,或具有析构函数的对象,或在递归定义中包含非平凡类型的对象),对象 creation/destruction 可以具有可见的副作用,因此何时发生可能很重要。编译器仍然可以在 as-if 规则下移动它们(即,程序集只需要像你写的那样运行),所以如果它能证明那些非平凡的 construction/destruction 操作不关心它们何时 运行(在标准形式意义上)它们可以被编译器移动。
在你的示例代码中是等效的,因为你使用了简单的类型,比如 int
。但一般来说,如果您将使用对象,这可能是错误的。
考虑以下示例:
void func()
{
SomeObj a, b;
SomeOtherObj c;
{
//Do something with a and b
}
}
在这种情况下,对象 a
和 b
不能在 c
之前被删除,因为对象总是以创建的相反顺序被删除。尽管从理论上讲,如果没有可观察到的副作用,一些编译器可能会在 c
之后重新安排 a
和 b
的创建,并在函数结束之前将其删除。
第二种情况
void func()
{
SomeObj a;
SomeOtherObj c;
{
SomeObj b;
//Do something with a and b
}
}
b
将在作用域关闭后立即删除,但 a
的行为与第一种情况相同。
对于第三种情况,a
的行为与第二种情况下的 b
相同。