变量创建是否取决于范围?

时间:2021-05-24 22:56:29

标签: c++ function c++11 variables scope

void someFunc()
{
int local0 = 0;
//some code
{
int local1 = 0;
//some code
}
int local2 = 0;
}

在进入someFunc的那一刻,所有三个局部变量都会被创建(分配在堆栈上)?还是先创建local0,再创建local1,再删除local1,再创建local2,退出时删除local0和local2?

3 个答案:

答案 0 :(得分:1)

所以,这个问题很难抽象地回答。编译器可以自由地重新排序您的代码,只要它与按顺序执行时编写的代码等效即可。也就是说,生成什么程序集是由编译器决定的。

使用此特定代码,并且单独使用此特定代码,执行任何优化的编译器很可能会意识到此函数是空操作,并省略它 (godbolt)。

也就是说,作为一般指导,C++ 不执行强制变量提升(与 JS 一样,see here)。也就是说,在声明变量之前使用变量名充其量是未定义的行为(最坏的情况是错误的语法)。

编辑:正如评论中提到的 Deduplicator,as-if rule 规范了编译器如何转换代码。它指定允许不影响程序“可观察行为”的代码更改。我喜欢 John Regehr 对可观察行为的定义 (here),尽管它有点同义反复:

<块引用>

可观察到的行为是那些产生副作用的行为。

答案 1 :(得分:1)

C++ 是根据抽象机器定义的。在抽象机中,操作按以下顺序发生:

  • local0 已创建
  • local1 已创建
  • local1 已销毁
  • local2 已创建

对真实机器的要求只是它必须产生与抽象机器相同的输出。没有关于如何产生该输出的要求。

对于这个特定的程序,真机可能不会创建任何变量,因为它们没有被使用,删除它们不会影响输出。

答案 2 :(得分:0)

如果您使用其构造和销毁具有副作用的变量,则更容易处理此问题。然后你可以看到他们来来往往。

所以,鉴于此:

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

这反过来又使一切变得清晰。

正如其他人提到的,如果变量是原始类型(并且不相互依赖),那么编译器可以自由地重新排列语句以生成更快的代码。

相关问题