【问题标题】:When do we practically need 'explicit xvalues'?我们什么时候实际上需要“显式 xvalues”?
【发布时间】:2016-01-19 07:07:09
【问题描述】:

xvalue的定义如下:

——一个xvalue(一个“eXpiring”值)也指一个对象,通常接近其生命周期的末尾(例如,它的资源可能会被移动)。 xvalue 是某些涉及右值引用的表达式的结果 (8.3.2)。 [ 示例:调用返回类型为右值引用的函数的结果是 xvalue。 ——结束示例]

我们是否会遇到实际需要使用返回类型为右值引用(即 xvalue)的函数的情况?

const int && Foo()
{
    // ...
}

移动语义将右值引用作为参数,而不是返回值。所以我认为情况并非如此。

【问题讨论】:

  • 标题中的“显式”是什么意思?
  • @MM 如果我编写了一个返回 xvalue 的函数并且我“知道”它,并且这是我的意图,我会说这是明确的,即使没有表示 xvalue 的语法关键字.

标签: c++ c++11


【解决方案1】:

返回右值引用可用于已经将右值作为参数的函数。一个简单的例子:

struct X {
    X() = default;
    X(X&& other) { std::cout << "move ctor\n"; }
    X(X const&) = delete;
    void log(std::string const& s){ std::cout << "log: " << s << "\n"; }
};

void sink(X&& x) { 
    x.log("sink"); 
}

X&& passOn(X&& in) {
    in.log("pass");
    return std::move(in);
}

X moveOn(X&& in) {
    in.log("move");
    return std::move(in);
}

int main() {
    sink(passOn(X()));
    std::cout << "===============================\n";
    sink(moveOn(X()));
}

Live demo →

第二个函数将调用移动构造函数来创建返回的对象,而第一个函数将传递它已经获得的引用。如果我们不返回原始引用而是对被引用对象的一部分的引用,这将更有用,例如

template<class T>
T&& getHead(std::vector<T>&& input) {
    return std::move(input.front());
}

【讨论】:

  • @Jarod42 不移到这里会调用已删除的复制构造函数。我不确定 NRVO 是否适用,因为函数内部没有对象。
  • 对于完美转发的过滤功能很有用。 +1!
【解决方案2】:

这正是std::move 的含义——std::move 执行的结果是一个 xvalue。除此之外很难说,因为在大多数情况下,从函数返回引用是一件坏事。但也许有人会想出另一个巧妙的用法来使用这种功能。

【讨论】:

  • @DeanSeo,确实,但是除了强制转换之外,您不能在返回类型中使用右值引用,因为从函数返回引用(无论它是什么类型)是错误的,除非它是const 和 const 右值引用没用
  • 抱歉删除了我之前的评论。顺便说一句,“正在返回的 const rvalue 引用”是一个 xvalue。所以递归地,返回 xvalues 实际上是没用的,你说? :p
  • @DeanSeo,我的意思是返回对在函数内堆栈上创建的事物的引用是不正确的。因此,除了std::move 的情况(我们从外部得到一些东西并返回一个右值引用)之外,我没有看到当我们可以使用右值引用作为返回类型时的用法示例。这并不意味着没有这样的用法——语言特性被一次又一次地重新发现。但目前我没有听说过这件事。
【解决方案3】:

我们是否会遇到实际需要使用返回类型为右值引用(即 xvalue)的函数的情况?

它在容器类中使用,例如 tuple 有一个 get 重载,如下所示:

template< std::size_t I, class... Types >
typename std::tuple_element<I, tuple<Types...> >::type&&
    get( tuple<Types...>&& t );

我假设 C++17 中的 std::optionalstd::variant 都会有类似的重载。

当然,唯一的一点是避免在某些非常特殊的情况下输入std::move,例如:

 auto x = std::get<1>( f() );

f 按值返回一个元组。

【讨论】:

  • 一个很好的例子,说明如何在不需要的地方保存甚至移动构造函数(即理论上它可能只是返回转换为纯右值的 xvalue,但这会不必要地需要移动或复制构造函数,它也不总是可用的)。
猜你喜欢
  • 1970-01-01
  • 2019-07-17
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多