析构函数在临时变量超出作用域之前被调用

13

我有一段代码,在VS2015中会失败,但在GCC下可以正常工作。我相信这是Visual Studio的错误,但想要确保我的decltype(auto)理解是正确的。

#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;
}
在 Visual Studio 下,zero_params 返回的字符串被推断为右值引用。此外,在 test1() 中调用 f 后返回值的析构函数被调用(这似乎是一个合理的 && 对象的销毁位置)。
在 GCC 下,返回的字符串不会被推断为右值引用。在我期望的 cout 语句中使用后析构函数被调用。
将返回类型指定为“string”而不是 decltype(auto),可以在 Visual Studio 中解决此问题,使用 remove_reference_t 在 test1 中对 f() 的返回值进行操作也可以解决。
我的期望是,由于 zero_params() 的函数签名是 string 而不是 string&&,所以我期望非引用类型会上升到 test1 的返回类型,如果它使用了 decltype(auto)。
这个评估正确吗?
后来编辑:
我发现在 VS2015 中解决这个问题的另一种方法是将给定给 test1 的函数包装在 lambda 中:
cout << test1(zero_params) << endl;

至:

cout << test1( [](auto&&... ps) { return zero_params(std::forward<decltype(ps)>(ps)...); } ) << endl;

5
没问题,f()是一个prvalue,所以decltype应该推断出std::string而不是std::string && - T.C.
3
请在MS Connect上提交一个错误报告,并在这里发布链接。如果decltype(auto)不是无用的话,这个问题在VS2015发布之前真正需要被修复... - ildjarn
不幸的是,MS Connect告诉我我没有权限提交错误报告。但是在Visual Studio中,我已经做了下一件最好的事情——使用他们的“哭脸”提交反馈,包括测试代码截图和描述。不幸的是,我认为这种方法无法跟踪?希望有人将其传递给正确的部门。 - qeadz
这是在VS2015预览版还是VS2015 CTP5中出现的问题?如果您能给我发送屏幕截图,我可以为您提交错误报告。然后我会在答复中包含一个可追踪的链接。 - Moby Disk
请不要在评论中回答,这篇帖子是破坏模型的完美例子。我们在评论中提供事实(随时可能消失),而半个答案则没有提供任何证据,反而交叉引用了评论(随时可能消失)。如果您想在回答问题之前与您的同行讨论问题,请尝试使用聊天室! - Lightness Races in Orbit
最新的 CTP 中有个 bug... 我认为是第五版。我会在周一检查并修正这个 Stack Overflow 的问题。 - qeadz
1个回答

2
根据评论,我们可以得出以下结论:
  • 这是 VS2015 预览版中的一个错误
  • 有解决方法
  • 该错误已被报告
该错误的原因是:
  • 编译器应该推断返回类型为字符串
  • 实际上它推断为字符串 &&
  • 因此过早地销毁了该值
解决方法为:
  • 不要使用 decltype(auto) 作为函数的返回类型
  • 在传递函数之前将其包装在 lambda 表达式中

能否将这些评论集成到这个答案中?评论是临时的。 - Lightness Races in Orbit
1
https://connect.microsoft.com/VisualStudio/feedback/details/1124457/decltype-auto-deducing-wrong-type-in-some-cases - T.C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接