2

I have the following code:

class thing {
    public:
        thing(const thing& x) { cout << "copy" << endl; }
        thing() { cout << "create" << endl; }
        ~thing() { cout << "destroy" << endl; }

        thing& operator=(const int& rhs) { cout << "assign" << endl; }
};

int foo(thing x) {
    return 5;
}

int main() {
    thing bar;
    thing newThing;
    newThing = foo(bar);

    getchar();
}

When I run this, at the point where my program reaches the getchar(), I expect to see the following output:

create // since bar is default constructed
create // since newThing is default constructed
copy // since bar gets passed by value into foo
destroy // since foo's local thing `x` is destructed when foo ends
assign // since the 5 returned by foo is assigned to newThing

Instead, I get this:

create
create
copy
assign
destroy

Note that assign and destroy have swapped from what I expected.

What's up with this? Why does the assignment appear to happen before the local x is destructed? Note that if I declare a local thing in the body of foo, it gets destructed before the assignment happens, as I would expect.

Ord
  • 5,693
  • 5
  • 28
  • 42
  • Have you disabled all compiler optimizations? If optimizations are enabled, the results may be altered by reordering and/or inlining. – Giulio Franco Oct 22 '13 at 19:41
  • 3
    Temporaries are destroyed at the end of the full expression they are a part of, so the temporary is destroyed after the assignment. See http://stackoverflow.com/questions/2506793/c-life-span-of-temporary-arguments – David Brown Oct 22 '13 at 19:42

2 Answers2

5

With this signature:

int foo(thing x) {
    return 5;
}

You are creating a function where the instance of thing is a parameter. Parameters are passed in by the caller of the method, that mean that the expression here:

newThing = foo(bar);

creates a temporary object of thing which is copied from bar. Those temporaries have a lifetime upto the end of the full expression, therefore the destructor of this temporary is called after the assignment happened.

Why is that so? Because the compiler only generates one function called foo and this function can not construct x locally - it would not know with which parameters to construct it. There could be multiple constructors which could be valid and several different sets of parameters. The compiler therefore must construct the temporary on the caller's side of the call.

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
1

Parameters are constructed and destructed by the caller, not by the method. 'foo()'s local thing' isn't foo()'s at all, it is the caller's: the caller destroys it.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Parameters passed by value are owned by and destructed by the called method, not the caller. For stdcall, this is necessary because the callee pops the stack before returning, meaning the parameter would disappear into oblivion before returning (thus the callee _must_ be the one to destruct the object). In cdecl, it could go either way because the caller fixes the stack, but VS at least (not sure about gcc and clang) still destruct the object from inside the method call before returning, perhaps for code bloat considerations. – Dwayne Robinson Mar 26 '15 at 18:20