qeadz
qeadz

Reputation: 1516

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;

Upvotes: 13

Views: 313

Answers (1)

Moby Disk
Moby Disk

Reputation: 3861

So based on the comments we can conclude:

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

Upvotes: 2

Related Questions