【问题标题】:Using auto vs const auto& to temporary keep result of method call使用 auto vs const auto& 临时保留方法调用的结果
【发布时间】:2020-09-22 17:54:33
【问题描述】:

假设我有

class Container {
  public:
    T getValue() const { return t; }
    const T& getCRef() const { return t; }
  private:
    const T t;
};

void f(const T& arg) { ... }

在函数内部临时绑定返回值的首选方法是什么?例如。我应该更喜欢什么,为什么?

void method(const Container& c) {
  auto t1 = c.getValue();
  auto t2 = c.getCRef();
  const auto& t3 = c.getValue();
  const auto& t4 = c.getCRef();

  // Notes from discussion:  
  // 1. Neither Container not object T changes during execution  
  // 2. I don't need to modify T, just passing it through  

  f(t1);
  f(t2);
  f(t3);
  f(t4);
}

我的理解是:

  • t1 将受益于复制省略,并将导致一个复制构造
  • t2 也会生成一个副本结构
  • t3 仍会导致返回的临时复制构造,然后由 const 引用绑定
  • t4 不应该是副本

正确吗?如果是这样,对于这种情况,我是否应该一直更喜欢const auto& 而不是auto?另外,当我可以保证引用与底层对象一样长时,我是否应该更喜欢getCRef() 接口而不是getValue()

【问题讨论】:

    标签: c++


    【解决方案1】:

    对吗?

    是的。

    如果是这样,对于这种情况,我是否应该一直更喜欢 const auto& 而不是 auto?

    这取决于你打算做什么。

    如果你想要一个副本,那么使用一个对象变量。如果要引用存储在其他地方的对象,请使用引用变量。

    另外,当我可以保证引用与底层对象一样长时,我应该更喜欢 getCRef() 接口而不是 getValue() 吗?

    同上。

    我的意图是将一个方法调用的未修改结果传递给另一个方法调用

    让我们假设对象在持续时间内没有变化

    如果T 是微不足道的,那么首选对象以避免不必要的间接。如果T 很重要,那么更喜欢引用以避免复制。如果你不知道T 是否微不足道,那就假设它不是。

    【讨论】:

    • 对于局部变量,我的意图是将一个方法调用的未修改结果传递给另一个,但不是立即,因此我需要一种方法来绑定返回值一段时间。问题是在这种情况下,我是否应该更喜欢const auto& 而不是auto,因为大多数时候它似乎更便宜(除了琐碎的类型)。我问的原因是似乎有人建议 const auto& 除了用于函数 args/return 之外,不应该使用,所以我想知道目前对此的共识是什么。
    • @nyrl pass unmodified result 您是打算传递成员在您从对象中获取它时所具有的值,还是传递成员在 f 被调用时所具有的值? what is the current consensus我怀疑你会得到足够的答案来获得一个体面的抽样来衡量是否有共识。
    • 一般来说这是一个很好的问题,但我们假设对象在method() 的持续时间内没有改变 - 所以复制不是严格要求的。
    【解决方案2】:

    对吗?

    是的。

    另外,当我可以保证引用与底层对象一样长时,我是否应该更喜欢getCRef() 接口而不是getValue()

    您不能保证子对象的引用生命周期。两者都在用户控制之下。

    内置类型和“小型”普通类型可以按值返回。
    对于其他人来说, const 参考似乎更好(避免额外的副本)。 与传递参数的规则基本相同。

    对于这种情况,我是否应该一直更喜欢 const auto& 而不是 auto

    如前所述,const auto 可以用来代替简单的auto 以获得类似的常量。

    auto 确保在容器类内部发生更改(或被销毁)时不会更改值。 (但实体在迭代器等情况下也可能无效)

    const auto& 不能保证这一点。

    auto 确实一直在复制。所以返回引用时需要额外的副本。
    当返回值时,它确保了临时的生命周期。

    const auto& 不会一直复制。 它延长了临时的生命周期,但这种结构有一些缺陷:

    const auto& c = std::string("hello")[0]; // dangling reference

    而字符串是临时的,我们使用返回引用的方法。

    两者都有其用途。

    【讨论】:

      【解决方案3】:

      我应该更喜欢 const auto& 而不是 auto

      const 关键字用于告诉程序员(并让编译器对此进行检查!)该变量不会在函数内部被修改。很好,尤其是在处理引用时,写下保证而不是仅仅通过代码检查来推断它。最好确保行为符合预期:您可能不需要修改某些内容,但该关键字会确保您不需要。

      为什么要使用const auto t 而不是const auto& t?我只能考虑两种情况:普通类型,以及你不能保证底层对象是常量并且你必须持有一个副本。

      这两个选项之间的区别在于,在一个选项中,您使用的是对对象的引用。这对于较大的变量可能很重要,但对于微不足道的变量则不然。以一个 int 为例。通过传递对 int 而不是 int 的引用,您将一无所获。不过,这样做并没有错。

      【讨论】:

      • 假设在我的示例中我会写const auto t1const auto t2。我这样说的原因是我通常看到人们写auto t = ...const auto& t = ...,但我还没有看到const auto t = ...
      • @nyrl:我看到并使用了三个版本。
      • @Jarod42 对不起,我夸大了。但是,为什么要使用const auto t 而不是const auto& t?我只能考虑两种情况:普通类型,以及你不能保证底层对象是常量并且你必须持有一个副本。
      • @nyrl 我不认为这个答案完全回答了你的问题,但const 的原因解释得很好
      • @nyrl:如果用特定类型替换auto,你会使用什么? auto 没什么新意。
      猜你喜欢
      • 2016-11-14
      • 2021-09-23
      • 1970-01-01
      • 2012-05-29
      • 2016-08-02
      • 1970-01-01
      • 2016-12-01
      • 2017-02-28
      相关资源
      最近更新 更多