【问题标题】:About rvalue reference in C++关于 C++ 中的右值引用
【发布时间】:2021-02-05 20:54:18
【问题描述】:
std::vector<std::string> func(int num) {
  std::vector<std::string> vec;
  int sum = 0;
  for(int i = 0; i < num; i++) {
    sum +=i;
    std::string s = std::to_string(sum);
    vec.emplace_back(s);
  }
  return vec;
}

下面的代码使用右值和左值引用有什么区别。

  std::vector<std::string> res = func(10);      // (case 1)
  std::vector<std::string> &&res = func(10);    // (case 2)
  std::vector<std::string> &res = func(10);   // I got an error!, case3
  const std::vector<std::string> &res = func(10);  // case4

问题:

  1. 右值引用(案例2)可以保存内存副本吗?比案例1
  2. 为什么 lvalue reference(case3) 出错但它与 const (case4) 一起工作?

【问题讨论】:

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


【解决方案1】:
  1. 当prvalue(“临时”)绑定到右值引用const左值引用时,临时的生命周期会延长到生命周期参考文献。
  2. const 左值引用不会延长纯右值的生命周期。

右值引用(案例2)可以保存内存副本吗?比案例1

它保留了单个返回对象的生命周期。见 1。

为什么左值引用(case3)出错

见 2。

但它适用于 const (case4)?

见 1。

【讨论】:

  • 感谢您的明确答复!那么右值 ref 返回类型呢?像:std::vector<:string> &&func(int num) { return std::move(vec); case2 之间有什么区别?
  • @eerorika 我读了很多次,但我认为您对“内存副本”在这里的含义是正确的。是的,它保存了内存中的“副本”。不,它不会保存 - 防止向新内存添加额外的副本。
  • @DrewDormann 哦,我想我明白你如何解释这个问题了。是的,这很不清楚。 “比 case1” 让我相信问题是 case 2 是否避免了 case 1 的副本。
  • @Andy 右值引用返回类型 not 纯右值,因此在任何这些情况下都不会发生生命周期延长。此生命周期延长仅适用于纯右值。
  • @DrewDormann 写得不好,我什至不知道prvalue和xrvalue这个词,学习了!感谢您的详细回复!
【解决方案2】:
  1. 右值引用(案例2)可以保存内存副本吗?比案例1

如果您的意思是“案例 2 是否 避免 案例 1 有一些副本”,那么答案是:不。如果 res 是一个自动变量,那么两者实际上是相同的。我建议编写案例 1,因为它更简单且不易混淆。

首先,从vec 移动到返回值。在实践中,优化器可以忽略这一举动。这种优化称为 NRVO(命名返回值优化)。

自 C++17 起:在这两种情况下,都由上述移动直接初始化(可能已被省略)。

C++17 之前:在这两种情况下,从返回值到初始化对象还有另一个移动。这个动作在实践中也可以省略。

  1. 为什么 lvalue reference(case3) 出错但它与 const (case4) 一起工作?

因为对非 const 的左值引用可能不会绑定到右值。

【讨论】:

  • 对于c++17,你是说它是完美的,说编译器只会使用函数范围内的内存扩展到func之外,没有复制或移动?跨度>
  • @Andy 如果 NRVO 是为了摆脱第一个动作,那么不会有任何动作。
  • 我知道了,非常感谢您的详细回答!
猜你喜欢
  • 1970-01-01
  • 2011-02-04
  • 2011-02-14
  • 1970-01-01
  • 2016-03-28
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
  • 2015-08-01
相关资源
最近更新 更多