【问题标题】:Rvalue reference behavior while returning from a function从函数返回时的右值引用行为
【发布时间】:2016-10-14 07:48:59
【问题描述】:

在下面的代码中:

class Myclass
{    
public:
    Myclass() = default;
    ~Myclass() = default;

    Myclass(Myclass&&) = default;
    Myclass& operator=(Myclass&&) = default;

    Myclass(const Myclass&) = delete;    
    Myclass& operator=(const Myclass&) = delete;
};

Myclass GetObj()
{
    Myclass obj;    
    return obj;
}

Myclass WrapperOfGetObj()
{
    Myclass&& Wrapobj = GetObj();

    return Wrapobj;
}

int main()
{
    return 0;
}

编译时,函数WrapperOfGetObjreturn Wrapobj 上出现错误。错误是

'Myclass::Myclass(const Myclass &)': 试图引用已删除的函数

这意味着它正在尝试调用deleted 复制构造函数。我知道Wrapobj 是左值,当它被返回时,它的行为应该与GetObj 方法中的obj 相同,即return 时调用移动构造函数那它为什么要找拷贝构造函数呢?我在这里错过了什么?

【问题讨论】:

  • 您需要使用std::move() 明确地创建一个右值。

标签: c++ c++11 c++14 rvalue-reference


【解决方案1】:

这里的问题是(正如 TC 在评论部分总结的那样)Wrapobj 是一个引用,而不是一个对象,因此隐式移动 - 即将返回的左值视为右值 - 在这种情况下不适用(参见[class.copy]/32)。

您可以通过以下方式解决此问题:

Myclass Wrapobj = GetObj();

而不是当前的:

Myclass&& Wrapobj = GetObj();

或者在返回时明确地std::move()ing Wrapobj。我个人建议选择第一个选项。

【讨论】:

  • this 可能是本主题的不错的额外阅读。
  • 表达式WrapobjMyClass类型的左值;表达式永远不会有引用类型(在 [expr]/5 调整之后)。问题是隐式移动仅适用于自动存储持续时间([class.copy]/32)的对象,并且引用不是对象。此外,“如果类型与函数的返回类型不同,编译器不会将返回语句中的命名左值视为右值”是不正确的,因为CWG 1579
  • @T.C.:标准中是否对此进行了澄清?回到我更活跃的那一天,我曾经坚信这一点,但后来我认为这可能取决于解释(参见Scott's blog post)。有最后一句话吗?无论如何,我会尝试更准确地改写它。
  • 我认为当它立即消失时考虑预调整类型不是很有用(因此括号内的限定符)。
  • @T.C.:我写了一个separate question
猜你喜欢
  • 2020-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 2014-03-29
  • 1970-01-01
相关资源
最近更新 更多