为什么使用引用作为迭代器

Why using a reference as an iterator

本文关键字:迭代器 引用 为什么      更新时间:2023-10-16

我正在学习std::vector的emplace((,并偶然发现了这段代码:

// vector::emplace
#include <iostream>
#include <vector>
int main ()
{
  std::vector<int> myvector = {10,20,30};
  auto it = myvector.emplace ( myvector.begin()+1, 100 );
  myvector.emplace ( it, 200 );
  myvector.emplace ( myvector.end(), 300 );
  std::cout << "myvector contains:";
  for (auto& x: myvector)
    std::cout << ' ' << x;
  std::cout << 'n';
  return 0;
}

我想知道为什么在 for 循环中使用引用 auto&x 而不是简单的副本,我尝试没有 &并且它的工作原理相同,这是避免复制的安全性还是性能技巧?

在此上下文中,autoauto& 之间的另一个区别是auto&允许您修改向量中的值。这可能是一个等待发生的不良错误。理想情况下,如果您打算仅将参考文献用于阅读,则应使用常量参考:const auto &

当矢量包含的对象超过基本数字或指针类型时,使用引用的好处是它不会将整个对象复制到临时对象。如果对象具有任何深层复制语义,或者可能是shared_ptr则可能会完全避免大量开销。

对于

基本类型,复制通常非常快,因此首选单个副本,但是如果要求编译器引用基本类型,然后多次使用该引用,您可以期望编译器优化器执行"正确的操作",因此对于模板编程,您应该优先使用 const-ref 而不是副本,以便在您不知道类型时保持代码简单。

就像你说的那么简单,它会是一个副本。所以这确实是一个性能技巧,但对于int来说,它不会更快,甚至可能更慢。但是如果你有一个有百万元素的std::vector<std::string>,那么它会有很大的不同。您可以自己尝试。

但是,如果要修改迭代容器的内容,则需要它。如果没有引用,您将更改副本,而不是容器内的元素。区别将在这里看到:

std::vector<int> numbers1 = {1,2,3,4};
std::vector<int> numbers2 = {1,2,3,4};
for(auto& x: numbers1) ++x;
for(auto x: numbers2) ++x;
assert(numbers1!=numbers2); // True

此外,我建议使用auto&&而不是auto&,因为它可以更好地与临时人员一起使用,请参阅例如此答案。