首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >变量的创建依赖于作用域吗?

变量的创建依赖于作用域吗?
EN

Stack Overflow用户
提问于 2021-05-25 06:56:29
回答 3查看 79关注 0票数 0
代码语言:javascript
复制
void someFunc()
{
int local0 = 0;
//some code
{
int local1 = 0;
//some code
}
int local2 = 0;
}

所有三个局部变量都将在进入someFunc时创建(在堆栈上分配)?还是先创建local0,然后创建local1,然后删除local1,然后创建local2,然后在退出时删除local0和local2?

EN

回答 3

Stack Overflow用户

发布于 2021-05-25 07:13:07

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

有了这个特定的代码,并且只有这个特定的代码,执行任何优化的编译器很可能意识到这个函数是一个无操作的函数,并省略它(godbolt)。

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

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

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

票数 1
EN

Stack Overflow用户

发布于 2021-05-25 08:33:20

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

  • local0 is created
  • local1 is created
  • local1 is destroyed
  • local2 is created

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

对于这个特定的程序,真实的机器可能不会创建任何变量,因为它们是未使用的,并且删除它们不会影响输出。

票数 1
EN

Stack Overflow用户

发布于 2021-05-25 08:32:48

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

因此,考虑到以下情况:

代码语言:javascript
复制
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"; }
};

然后我们可以将您的示例重写为:

代码语言:javascript
复制
void someFunc()
{
    Foo local0 (0);
    {
        Foo local1 (1);
    }
    Foo local2 (2);
}

它给出了输出:

代码语言:javascript
复制
Foo constructor #0
Foo constructor #1
Foo destructor #1
Foo constructor #2
Foo destructor #2
Foo destructor #0

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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67679781

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档