2

I have c++ code that works properly in Debian (gcc (Debian 4.7.2-5) 4.7.2), but fails in Ubuntu (gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2). I'm getting stack space reused between variables, similar to what is described in these questions:

In C, do braces act as a stack frame?

C++ stack and scope

except I'm not having nested scopes. Instead code looks similar to this:

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

I could mitigate this issue by allocating on the heap, but I'm wondering what can I do to make sure that local variables are left in place? Would assigning visitors to local variables be enough to ensure they won't be reused? Does standard provides any promise on the stack variables after their last use in function code?

Community
  • 1
  • 1
Slartibartfast
  • 8,735
  • 6
  • 41
  • 45
  • _"I have c++ code that works properly"_ If your program depends on the temporaries not being created at the same location then it does not work properly, it only _appears_ to work properly _sometimes_. You have a bug that should be fixed, not worked around. – Jonathan Wakely Mar 09 '15 at 14:09

2 Answers2

4

what can I do to make sure that local variables are left in place?

Either use (named) local variables, not temporaries; or modify addVisitor to store a copy of the visitor rather than a reference to it, if that's feasible.

Would assigning visitors to local variables be enough to ensure they won't be reused?

Yes.

Does standard provides any promise on the stack variables after their last use in function code?

Temporaries (unnamed objects created during an expression, such as the visitors you create) live until the end of the full-expression that creates them. So they last until the call to addVisitor returns, but are destroyed before the next line.

Local variables (automatic variables declared within a block of code) last until the program leaves the innermost block in which they are declared. When that happens, each local variable from that block is destroyed in the reverse order of their declarations. So in the following:

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

it's guaranteed that walker will be destroyed before the visitors, so it will not contain any dangling references even in its destructor.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
2

Visitor1() is not a local variable, it's a temporary. The lifetime of a temporary ends when the full-expression in which it appears ends.

If you need to preserve them, use local variables for them instead of temporaries.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Without knowing what `addVisitor` does (e.g. does it make a copy of its second argument or not?), it cannot be said what the lifetime of the temporaries (or copies thereof) in the OP's code is. Nonetheless, the behavior he describes seems to point to no copying, which seems like the wrong thing to do here. – rubenvb May 07 '13 at 08:03
  • @rubenvb Nothing can affect the lifetime of the temporaries in these expressions. The lifetime of their copies, if any, is a different matter entirely, but it wouldn't affect the "stack frame" of the calling function in the slightest. – Angew is no longer proud of SO May 07 '13 at 08:07
  • That's all true, but normally not a problem. This suggests that the `Visitor` class's copy constructor doesn't have value semantics, which is to say that it doesn't copy the state from the temporarily properly into the tree node (when asked to by `addVisitor`). – Tony Delroy May 07 '13 at 08:14
  • @rubenvb While the OP doesn't say so explicitly, his choice of names and the example code make it clear that `Vistor1` and `Visitor2` are polymoprhic instances of the same base. As such, `TreeWalker` cannot really copy them (unless there are additional constraints, such as the presence of a `clone` function). Logically, it wouldn't copy them, since the copy would require dynamic allocation. – James Kanze May 07 '13 at 08:23