c++中堆栈分配数据的生命周期

Posted

技术标签:

【中文标题】c++中堆栈分配数据的生命周期【英文标题】:Life span of stack allocated data in c++ 【发布时间】:2013-05-01 02:38:04 【问题描述】:

我的 c++ 代码在 Debian (gcc (Debian 4.7.2-5) 4.7.2) 中正常工作,但在 Ubuntu (gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2) 中失败。我正在变量之间重用堆栈空间,类似于这些问题中描述的内容:

In C, do braces act as a stack frame?

C++ stack and scope

除了我没有嵌套范围。相反,代码看起来类似于:

TreeWalker walker;
walker.addVisitor(nodeType1, Visitor1());
walker.addVisitor(nodeType2, Visitor2());
...
walker.walkTree(tree);

我可以通过在堆上分配来缓解这个问题,但我想知道我可以做些什么来确保局部变量留在原地?将访问者分配给局部变量是否足以确保它们不会被重用?标准是否在函数代码中最后一次使用堆栈变量后对它们提供任何承诺?

【问题讨论】:

“我的 c++ 代码可以正常工作” 如果您的程序依赖于未在同一位置创建的临时文件,则它无法正常工作,它只有 似乎有时可以正常工作。您有一个应该修复而不是解决的错误。 【参考方案1】:

我可以做些什么来确保局部变量留在原地?

要么使用(命名)局部变量,而不是临时变量;或修改addVisitor 以存储访问者的副本而不是对其的引用,如果可行的话。

将访问者分配给局部变量是否足以确保它们不会被重复使用?

是的。

在函数代码中最后一次使用堆栈变量后,标准是否对堆栈变量提供任何承诺?

临时对象(在表达式期间创建的未命名对象,例如您创建的访问者)一直存在到创建它们的完整表达式结束。所以它们会一直持续到对addVisitor 的调用返回,但在下一行之前被销毁。

局部变量(在代码块中声明的自动变量)一直持续到程序离开声明它们的最里面的块。发生这种情况时,该块中的每个局部变量都会按照其声明的相反顺序被销毁。所以在下面:


    Visitor1 visitor1;
    Visitor2 visitor2;
    TreeWalker walker;
    walker.addVisitor(nodeType1, visitor1);
    walker.addVisitor(nodeType2, visitor2);
    //...
    walker.walkTree(tree);

保证walker会在访问者之前被销毁,因此即使在其析构函数中也不会包含任何悬空引用。

【讨论】:

【参考方案2】:

Visitor1() 不是局部变量,它是临时变量。临时的生命周期在它出现的完整表达式结束时结束。

如果您需要保留它们,请为它们使用局部变量而不是临时变量。

【讨论】:

在不知道 addVisitor 做什么的情况下(例如,它是否复制其第二个参数?),不能说 OP 代码中临时对象(或其副本)的生命周期是多少是。尽管如此,他所描述的行为似乎表明没有复制,这似乎是错误的做法。 @rubenvb 没有什么可以影响这些表达式中临时对象的生命周期。它们的副本的生命周期(如果有的话)完全是另一回事,但它丝毫不会影响调用函数的“堆栈框架”。 没错,但通常不是问题。这表明Visitor 类的复制构造函数没有值语义,也就是说,它不会将状态从临时正确地复制到树节点中(当addVisitor 要求时)。 @rubenvb 虽然 OP 没有明确说明,但他选择的名称和示例代码清楚地表明 Vistor1Visitor2 是同一个基的多态实例。因此,TreeWalker 不能真正复制它们(除非存在其他约束,例如存在 clone 函数)。从逻辑上讲,它不会复制它们,因为复制需要动态分配。

以上是关于c++中堆栈分配数据的生命周期的主要内容,如果未能解决你的问题,请参考以下文章

C++ 炼气期之变量的生命周期和作用域

java 数据存储

c++类中 各种成员的生命周期?

ES索引生命周期管理

C++服务器设计:设备连接的生命周期管理

Flutter 中的生命周期