【问题标题】:std::unordered_set return type by reference vs value [duplicate]std::unordered_set 通过引用与值返回类型[重复]
【发布时间】:2017-06-14 12:49:41
【问题描述】:

免责声明:我是 C++ 新手。

我有一个这样的代码块:

  using BucketType = std::unordered_set<Bucket, BucketHash, BucketEqual>;

  const BucketType& Range::buckets(int64_t value) {
    BucketType buckets;
    ...
    return std::move(buckets);
  }

调用者这样调用这段代码:

  Range range;
  auto buckets = range.buckets(11);

问题:

当我像上面的代码一样返回存储桶的引用时,buckets.size() 给出了140732261909672 但是,我只在我的实际逻辑中添加了 2 个存储桶。当我将代码更改为返回值而不是引用时,它工作得非常好。

有关此代码可能有什么问题的任何指针?

【问题讨论】:

  • 尝试从buckets的返回类型中删除&。
  • 不要使用std::move 来返回值,除非在极少数情况下它确实是最好的。如果可能的话,不仅返回值会被移出,使用std::move 实际上会阻止 (N)RVO 的更好结果。现在这通常适用于按值返回而不是按引用。我不确定您希望这个返回值的行为是什么。
  • 短版:不要使用std::move,除非您知道它的作用和使用方法。
  • 还有一个更短的版本:不要返回对自动范围内的对象的引用。这总是一个错误(除非从未使用过引用,但在这种情况下,返回它是没有意义的)。

标签: c++ c++11 stl std


【解决方案1】:

让我们考虑一下您的 buckets 函数:

const BucketType& Range::buckets(int64_t value) {
    BucketType buckets;
    ...
    return std::move(buckets);
}

这里创建一个BucketType类型的本地对象,移动到函数的返回值位置,然后返回绑定到这个临时的const引用 对象。毫无疑问,它会导致未定义的行为

编写此类函数的正确方法是简化代码并去掉const BucketType&amp;std::move(buckets)

BucketType Range::buckets(int64_t value) {
    BucketType buckets;
    ...
    return buckets;
}

现在buckets 可用于NRVO(命名返回值优化)。这意味着所有现代编译器都在此处执行复制省略,并在使用buckets函数初始化它们时直接构造BucketType对象(而不在函数的返回值位置创建临时对象):

auto buckets = range.buckets(11); // No unnecessary copies here

【讨论】:

  • 如果你删除const返回对象然后返回凸轮被移动,如果由于某种原因不能删除副本(不可能在不知道...代表什么的情况下保证删除.)
  • @juanchopanza 是的,绝对!
猜你喜欢
  • 2019-06-13
  • 2014-07-28
  • 2022-11-26
  • 1970-01-01
  • 2011-04-17
  • 1970-01-01
  • 2015-06-06
  • 2012-06-03
  • 2016-12-04
相关资源
最近更新 更多