Joe C Joe C - 2 months ago 8
C++ Question

The life range of a temporary object created at callsite arguments

I have the following code, was wondering when Foo's destructor is called.

#include <iostream>

class Foo {
public:
Foo() {
}
~Foo() {
std::cout << "destruct" << std::endl;
}
};

void go(Foo f) {
std::cout << "go" << std::endl;
}

int main() {
go(Foo());
std::cout << "main" << std::endl;
return 0;
}


If I run the code, I got the following output

go
destruct
main


It shows Foo's destructor is called after go is done. My gcc is 4.8.3.

I had thought the temporary Foo's object should be deleted after it is copied to go's argument. But this is not the case, and only one object of Foo exists. Is this expected or undefined in terms of compiler's implementation?

Answer

It's an optimization permitted by the C++ Standard. And really, any compiler should take on such optimization.

The C++ standard draft, [class.temp/2] says and I quote (relevant parts only; emphasis are mine):

The materialization of a temporary object is generally delayed as long as possible in order to avoid creating unnecessary temporary objects. .....

Example:

class X {
public:
  X(int);
  X(const X&);
  X& operator=(const X&);
  ~X();
};

class Y {
public:
  Y(int);
  Y(Y&&);
  ~Y();
};

X f(X);
Y g(Y);

void h() {
  X a(1);
  X b = f(X(2));
  Y c = g(Y(3));
  a = f(a);
}

X(2) is constructed in the space used to hold f()'s argument and Y(3) is constructed in the space used to hold g()'s argument.

Formerly, in n3690, it said:

An implementation might use a temporary in which to construct X(2) before passing it to f() using X’s copy constructor; alternatively, X(2) might be constructed in the space used to hold the argument

Comments