【问题标题】:C++11 local named references to return value (xvalue)?C ++ 11本地命名引用返回值(xvalue)?
【发布时间】:2013-01-07 00:06:38
【问题描述】:

我们有以下类型X和函数f

struct X { ... };

X f() { ... };

现在考虑另一个函数g的三个替代定义:

(1)

void g()
{
    X x = f();

    ...
}

(2)

void g()
{
    X& x = f();

    ...
}

(3)

void g()
{
    X&& x = f();

    ...
}

三种不同情况之间的定义行为(或潜在行为)有何不同? (假设占位符 '...' 代码在三种情况下是相同的)

更新:

如果g 返回X 会怎样:以下合法且正确吗?

X g()
{
    X&& x = f();

    ...

    return move(x);
}

(这个动作有必要吗,有什么作用吗?)

您是否希望 RVO 链接,以便下面的代码生成相同的代码?

X g()
{
    X x = f();

    ...

    return x;
}

【问题讨论】:

标签: c++ c++11


【解决方案1】:

2 是非法的。其他两个基本相同——xX 类型的可变左值,当g() 返回时,它的生命就结束了。

当然,严格来说,第一个调用移动构造函数(但它是某些 RVO/NRVO 动作的主要候选者)而第三个不调用,所以如果 X 是不可移动的(非常奇怪...),第三种情况是合法的但第一个不是,第一个可能更贵。然而,编译器选项和不可移动类型的实际情况是,这几乎完全是一种技术性问题,如果您能实际演示任何此类情况,我会感到惊讶。

【讨论】:

  • 实际上他们没有。
  • @AndrewTomazosFathomlingCorps 您应该尽可能使用 (1),因为它更简单并且不依赖于 C++ 奥秘知识。仅在必要时使用 (3)。
【解决方案2】:

表达式f()按值返回,所以它是一个prvalue

  1. 这将创建一个X 类型的新对象,该对象使用表达式f() 进行初始化,该表达式是X 类型的prvalue。如何构造新的X 对象取决于它是否具有移动构造函数。如果它有一个移动构造函数(或一个接受X rvalues 的模板构造函数),它将被调用,否则如果它有一个将被调用的复制构造函数。在实践中,编译器几乎肯定会忽略构造函数调用,但适当的构造函数必须是可访问的且不能被删除。

  2. 这甚至无法编译,您会因为在发布前没有尝试而遭到反对!

  3. 这会创建一个X&& 类型的新引用,并通过将其绑定到f() 返回的纯右值来初始化它。该prvalue的生命周期将延长至与引用x相同的生命周期。

假设移动/复制被省略,行为上的差异可能没什么,但是(1)和(3)之间的语义存在差异,因为一个为构造函数重载决议,这可能会失败,另一个总是有效的。

如果 g 返回 X 怎么办:以下合法且正确吗?

这是合法的。 move 是不必要的,有一条特殊规则说,当按值返回局部变量时,首先会完成构造函数查找,就好像该变量是右值一样,所以如果 X 有一个移动构造函数,它将被使用,无论是否你使用move(x)。 RVO 应该“连锁”。如果g 返回X&,这两种情况都会出现问题,因为它要绑定的对象会在g 末尾超出范围。

(NB 始终限定 std::move 以防止 ADL 是一种很好的做法。std::forward 也是如此。如果您的意思是调用 std::movestd::forward 则要明确,不要依赖于没有重载范围或可见,moveforward 不是像 swap 这样的自定义点。)


与其通过提出关于 SO 的问题来学习 C++,为什么不编写代码来测试发生的事情并向自己证明呢?使用 G++,您可以使用 -fno-elide-constructors 标志来关闭构造函数省略以查看在没有省略的情况下会发生什么,并且当不使用该标志(默认)时,您可以轻松测试 RVO 是否为自己“链接”。

【讨论】:

  • +1 总体答案,但是通过编写代码来学习 C++ 并查看它是否有效并不是学习未定义行为的好方法> 到处都是
  • 例如,一个体面的编译器会警告返回对临时对象的引用,并且肯定会显示 (2) 甚至无效!总的来说不好,但几乎可以回答这个 SO 问题的每个部分。
  • (2) 甚至无法编译,实验很容易告诉你这一点,所以你在询问之前显然没有尝试过最粗略的实验。而且问题不是关于 _un_defined 行为,主要是关于完全定义的行为会发生什么
  • 我不同意“移动是不必要的”。他命名了一个右值引用,而不是一个具有自动存储持续时间的对象变量。
  • @JohannesSchaub-litb,很好,谢谢!所以这是更喜欢 (1) 到 (3) 的一个很好的论据,因为它不会阻止省略
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-24
相关资源
最近更新 更多