Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

destructor called before temporary should be out of scope

I have a bit of code which fails under VS2015, but works under GCC. I'm pretty sure the bug is with Visual Studio but want to be sure that my understanding of decltype(auto) is correct.

#include <iostream>
using namespace std;

string zero_params()
{
  return "zero_params called.";
}

template< typename F >
auto test1( F f ) -> decltype(auto)
{
  return f();
}

int main() {
  cout << std::is_rvalue_reference< decltype(test1(zero_params)) >::value << endl;
  cout << test1(zero_params) << endl;

  cout << "Done!" << endl;
  return 0;
}

Under Visual Studio the string returned by zero_params is deduced to be an rvalue reference. Furthermore the destructor of that object is called inside test1() where the return from the call to f happens (which seems a reasonable place to destruct a && object).

Under GCC the string returned is not deduced to be an rvalue reference. The destructor is called after use in the cout statement as I'd expect.

Specifying the return type to be 'string' instead of decltype(auto) under Visual Studio fixes it, as does using remove_reference_t on the return of f() inside test1.

My expectation would be that GCC is correct as the function signature for zero_params() is string, not string&& so I would expect the non-reference to 'bubble up' to the return type of test1 if it uses decltype(auto).

Is this a correct assessment?


LATE EDIT:

Another way I've found to get around this with VS2015 is to wrap the function given to test1 in a lambda:

cout << test1(zero_params) << endl;

to:

cout << test1( [](auto&&... ps) { return zero_params(std::forward<decltype(ps)>(ps)...); } ) << endl;
like image 298
qeadz Avatar asked Feb 10 '15 19:02

qeadz


People also ask

Are destructors automatically called whenever an object goes out of scope?

A destructor is a member function that is invoked automatically when the object goes out of scope or is explicitly destroyed by a call to delete . A destructor has the same name as the class, preceded by a tilde ( ~ ).

What is the order of destructor call?

The destructors will be called in the order s5 , s4 , s3 , s2 , s1 . This is a general rule: if two objects' lifetimes overlap, then the first to be constructed will be the last to be automatically destroyed.

Is destructor called on exit?

No, most destructors are not run on exit() . Essentially, when exit is called static objects are destroyed, atexit handlers are executed, open C streams are flushed and closed, and files created by tmpfile are removed.

Which object's destructor will be called first?

The destructor for a class object is called before destructors for members and bases are called. Destructors for nonstatic members are called before destructors for base classes are called.


1 Answers

So based on the comments we can conclude:

  • This is a bug in VS2015 preview
  • There are workarounds
  • The bug has been reported

The bug is that:

  • The compiler should have deduced the return type to be string
  • It actually deduced it to be string &&
  • Thus it destroyed the value prematurely

The workarounds are:

  • Don't use decltype(auto) for the function's return type
  • Wrap the function in a lambda expression before passing it in
like image 192
3 revs Avatar answered Sep 20 '22 00:09

3 revs