Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is destructor called for temporary objects returned from a function in C++?

Tags:

c++

raii

Here's a code from Stroustrup's "The C++ Programming Language" that implements a finally which I cannot quiet understand where the destructor gets called.

template<typename F> struct Final_action
{
  Final_action(F f): clean{f} {}
  ~Final_action() { clean(); }
  F clean;
}

template<class F> 
Final_action<F> finally(F f)
{
  return Final_action<F>(f);
}

void test(){
  int* p=new int{7};
  auto act1 = finally( [&]{delete p;cout<<"Goodbye,cruel world\n";} );
}

I have two questions around this:

  1. According to the author, the delete p only gets called once: when act1 goes out of scope. But from my understanding: first, act1 will be initialized with the copy constructor, then the temporary object Final_action<F>(f) in the function finally gets destructed, calling delete p for the first time, then a second time at the end of the function test when act1 is out of scope. Where am I getting it wrong?

  2. Why is the finally function needed? Can't I just define Final_action act1([&]{delete p;cout<<"Goodbye,cruel world\n"})? Is that the same?

Also, if anyone can think of a better title, please modify the current one.

UPDATE: After some further thinking, I'm now convinced that the destructor may be called thrice. The additional one is for the temporary objected auto-generated in the calling function void test() used as the argument to the copy constructor of act1. This can be verified with -fno-elide-constructors option in g++. For those who have the same question as me, see Copy elision as well as Return value optimization as pointed out in the answer by Bill Lynch.

like image 575
btshengsheng Avatar asked Sep 17 '15 14:09

btshengsheng


Video Answer


1 Answers

You are correct, this code is broken. It only works correctly when return value optimizations are applied. This line:

auto act1 = finally([&]{delete p;cout<<"Goodbye,cruel world\n"})

May or may not invoke the copy constructor. If it does, then you will have two objects of type Final_action and you will thus call that lambda twice.

like image 187
Bill Lynch Avatar answered Sep 19 '22 15:09

Bill Lynch