【问题标题】:`xvalue` behavior in C++11/14C++11/14 中的 `xvalue` 行为
【发布时间】:2016-11-06 15:22:08
【问题描述】:
class Myclass
{    
public:
    Myclass() = default;
    ~Myclass() = default;
    Myclass(Myclass&&) = default;
    Myclass& operator=(Myclass&&) = default;

    Myclass(const Myclass&) = delete;

    Myclass& operator=(const Myclass&) = delete;
    int i = 0;
};

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

Myclass WrapperOfGetObj()
{
    Myclass&& Wrapobj = GetObj();
    Wrapobj.i = 1; // Will it work?

    return std::move(Wrapobj);
}

int main()
{
    return 0;
}

我有几个问题: 1) 在WrapperOfGetObj 函数中,Wrapobjxvalue,所以我可以为它的任何成员赋值(xvalue - 即将到期!!)
2)xvalue的存储是什么?这不是自动存储吗?
3) 当xvalue 变成glvalue 和当它变成rvalue 时。(上面上下文中的任何例子都会让我明白这一点)。

【问题讨论】:

标签: c++ c++11 c++14 xvalue


【解决方案1】:

表达式Wrapobj 是一个左值。所有命名变量都是左值。

我认为您在变量的声明类型与由变量名称组成的表达式的类型和值类别之间混淆了。

decltype(Wrapobj) 给出MyClass&&。当有人说“Wrapobj 是一个右值引用”时,他们正在谈论声明的类型。但是当Wrapobj 用于表达式时,它的类型为MyClass,值类别为lvalue

没有引用类型的表达式。此外,表达式的类型和值类别与表达式是否表示临时对象没有直接关系。

对于您的问题 2:“xvalue”是表达式的值类别。表达式没有存储空间。对象有存储。引用可能会或可能不会使用存储(它是未指定)。一定要区分引用的存储和它所引用的对象的存储。

GetObj() 的返回值是一个临时对象。该标准实际上并没有指定临时对象的存储持续时间,尽管常见的实现使用堆栈(类似于自动对象)。我认为 C++17 可能正在改进该领域的标准措辞。

【讨论】:

  • 所以根据 u Myclass WrapperOfGetObj() { Myclass&& Wrapobj = GetObj(); Wrapobj.i = 1; // 它会工作吗?返回 std::move(Wrapobj); } Wrapobj.i = 1;可能无效??
  • @gauravbharadwaj 您的示例代码很好,可以修改临时对象(只要它们不是 const)
  • 所以@M.M 我只是对GetObj() 和WrapperOfGetObj() 两者都返回lvalue 感到困惑,首先调用move constructor,然后调用copy constructor
  • @gauravbharadwaj 都按值返回(不是“左值”)您的问题没有说明何时调用构造函数;如果您不确定,最好在您的代码示例中发布一个新问题(以及让您确信调用了哪些构造函数的输出)
  • 那么 const Myclass&& Wrapobj = Myclass(); 有什么区别?和 const Myclass& Wrapobj = GetObj(); ?谢谢!
【解决方案2】:

这些答案会有所帮助...

Do rvalue references allow dangling references?

What are rvalues, lvalues, xvalues, glvalues, and prvalues?

Real life examples of xvalues, glvalues, and prvalues?

Myclass WrapperOfGetObj()
{
    Myclass&& Wrapobj = GetObj();
    Wrapobj.i = 1; // Will it work?

    return std::move(Wrapobj);
}

1) 在 WrapperOfGetObj 函数中,Wrapobj 是 xalue,所以我可以为它的任何成员赋值(xvalue - 即将过期!!)

Wrapobj 是对 GetObj() 返回的纯右值的右值引用。该纯右值的生命周期已延长至右值引用 Wrapobj 的生命周期,因此访问 .i = 1 即可。

2) xvalue 的存储是什么?这不是自动存储吗?

Wrapobj 的引用对象具有自动存储功能,并会在 WrapperOfGetObj 完成时销毁。

3) 当 xvalue 变成 glvalue 和当它变成 rvalue 时。(上面上下文中的任何例子都会让我明白这一点)。

xvalue 始终是 glvalues。 glvalues 只是所有“xvalues”和所有“lvalues”的并集,意味着“有身份”。 xvalues 也总是 rvalues,它只是所有“xvalues”和所有“prvalues”的并集,意思是“可以移动”。

因此,在上面的示例中,Wrapobj 是一个左值(因为它具有标识)、一个右值(因为它可以移动)和一个 xvalue(因为它既可移动又具有标识)。

当您从 WrapperOfGetObj() 返回 std::move(Wrapobj) 时,您正在从 std::move 返回的 xvalue 构造一个新的纯右值。

【讨论】:

  • 表达式Wrapobj 是左值,不是右值也不是xvalue。 “lvalue, xvalue, prvalue”这三个类别不重叠,任何表达式都恰好是三者之一。您还将表达式与对象混合在一起,例如“构造一个新的prvalue”应该是“构造一个新的临时值”。 “prvalue”指的是表达式,而不是对象。
  • 正如@m-m 所说,请再次查看您的答案。
猜你喜欢
  • 1970-01-01
  • 2017-07-15
  • 2017-09-12
  • 2014-07-30
  • 2016-12-31
  • 2015-12-29
  • 2013-09-14
  • 1970-01-01
  • 2021-05-24
相关资源
最近更新 更多