void someFunc()
{
int local0 = 0;
//some code
{
int local1 = 0;
//some code
}
int local2 = 0;
}所有三个局部变量都将在进入someFunc时创建(在堆栈上分配)?还是先创建local0,然后创建local1,然后删除local1,然后创建local2,然后在退出时删除local0和local2?
发布于 2021-05-25 07:13:07
因此,这个问题很难抽象地回答。编译器可以自由地重新排序您的代码,只要它与顺序执行时编写的代码等效即可。也就是说,生成什么程序集取决于编译器。
有了这个特定的代码,并且只有这个特定的代码,执行任何优化的编译器很可能意识到这个函数是一个无操作的函数,并省略它(godbolt)。
也就是说,作为一般指导,C++不执行强制变量提升(与JS、see here一样)。也就是说,在声明变量之前使用它们的名称,充其量是未定义的行为(最坏的情况是语法错误)。
编辑:正如评论中提到的去重工具,as-if rule规范了编译器如何转换代码。它指定允许不影响程序的“可观察行为”的代码更改。我喜欢John Regehr对可观察行为(here)的定义,尽管它有点同义反复:
可观察的行为是那些产生副作用的行为。
发布于 2021-05-25 08:33:20
C++是用抽象机器来定义的。在抽象机器中,操作按以下顺序发生:
local0 is createdlocal1 is createdlocal1 is destroyedlocal2 is created对真实机器的要求仅仅是它必须产生与抽象机器相同的输出。没有关于它如何产生输出的要求。
对于这个特定的程序,真实的机器可能不会创建任何变量,因为它们是未使用的,并且删除它们不会影响输出。
发布于 2021-05-25 08:32:48
如果使用构造和销毁有副作用的变量,则更容易处理此问题。然后你可以看到他们来来去去。
因此,考虑到以下情况:
class Foo
{
int m_i;
public:
Foo (int i) : m_i (i) { std::cout << "Foo constructor #" << i << "\n"; }
~Foo () { std::cout << "Foo destructor #" << m_i << "\n"; }
};然后我们可以将您的示例重写为:
void someFunc()
{
Foo local0 (0);
{
Foo local1 (1);
}
Foo local2 (2);
}它给出了输出:
Foo constructor #0
Foo constructor #1
Foo destructor #1
Foo constructor #2
Foo destructor #2
Foo destructor #0这反过来又让一切变得清晰起来。
正如其他人所提到的,如果变量是原语类型(并且彼此不依赖),那么编译器可以自由地重新排序语句,以便生成更快的代码。
https://stackoverflow.com/questions/67679781
复制相似问题