微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在主存储器中的循环内分配局部变量

如何解决在主存储器中的循环内分配局部变量

假设我有一个 for 循环和一个局部变量:

for(int i=0;i<10;i++){ // Outer loop

    int p[10]; // Local variable

    for(int j=1;j<10;j++){ // Inner loop
    
        p[j] = p[j-1]+1;
    }
}

当所有编译器优化都关闭时,很明显,对于外循环的第一次迭代,数组p将被分配到主内存中。

但是,分配给 p 的内存是否在 循环的第一 迭代结束时在主内存中释放并分配在循环的后续迭代开始后再次?

在我看来,循环的范围和方法的范围是不同的。函数执行完毕后,局部变量被释放,内存返回给操作系统。

但是 for 循环,当作用域在每次迭代结束时结束时,局部变量不会因为它们在不久的将来(后续迭代)中使用而被释放。只有在循环结束后才执行,局部变量才应该从主内存中释放。

如有错误请指正。

解决方法

C++ 的行为是根据抽象机器定义的。在这台机器中,从每个进入块的开始(块中代码的执行开始)到块的执行结束,具有自动存储持续时间的对象的内存都被保证存在。与 int p[10] 关联的块是由 { 紧跟在 for(int I=0;i<10;i++) 之后创建的块。此块的执行在 for 循环的每次迭代中开始和结束。

虽然编译器很可能通过分配一次堆栈空间来实现这个循环(可能是在它所在的函数启动时,而不仅仅是在到达 for 循环时),因此用于实现的内存int p[10] 保持分配给整个循环,而不仅仅是每次迭代,程序的行为是根据抽象机定义的。

这意味着虽然堆栈空间仍然保留,但编译器的优化不需要以这种方式运行。优化可能会导致代码在每次迭代中“忘记”p 元素中的值。

例如,如果我们在 macOS 10.14.6 和 -O3 -std=c++17 上使用 Apple Clang 11.0 执行此代码:

    int p[10];
    for (int i = 0; i < 10; i++)
    {
        if (i == 0)
            p[0] = 0;
        else
            p[0] = p[0]+1;
        for (int j = 1; j < 10; j++)
        {
            p[j] = p[j-1] + 1;
        }
        if (i == 9)
            std::cout << p[0] << '\n';
    }

则输出为“9”,因为 p[0] 在第一次迭代中设置为 0,并在以后的每次迭代中递增。但是,我们将 int p[10]; 移动到循环内,输出为“0”,因为编译器优化没有在迭代之间保留 p[0] 的值。

,

p 的作用域是外循环,因此每次迭代时它都会在堆栈上被销毁和重新创建。唯一未被销毁的变量是 i,但直到外循环完成。当 i=0 时的 int p[10]; 不同于当 i=1 时的 int p[10]; 等等,所以当 i=1 时,之前的 p 已经消失了。任何其他优化(或假设)都依赖于编译器、架构等。

澄清一下,p 存在于堆栈中,其作用域将决定何时释放内存(与堆上的变量不同)。

可能有点吹毛求疵,但请使用现代 C++ 容器,例如 std::arraystd::vector,而不是原始的普通 C 数组。

要改进资源管理,请查看 RAII

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。