关于迭代 std::vector 的 C++ 问题

C++ question about iterating over std::vector

提问人:troppapolvere 提问时间:9/30/2022 最后编辑:Adrian Moletroppapolvere 更新时间:9/30/2022 访问量:87

问:

我的问题(“为什么它不起作用?”)涉及下面的小样本。

当我运行这个(之后)时,我得到:g++ testThis.cc -o testThis

printing 101
printing 102
printing 103
                                 printing 100
                                 printing 100
                                 printing -1021296524

这应该不是超出范围的问题,那么为什么要制作向量本身的本地副本呢?myHolder

它应该在课堂上保持舒适。

#include <vector>
#include <iostream>

class stdHolder {

public:

  stdHolder();

  std::vector<int> getSV() const {return _myVector;}

private:

  std::vector<int> _myVector;

};

stdHolder::stdHolder() {

  _myVector.push_back(1);
  _myVector.push_back(2);
  _myVector.push_back(3);

}

int main() {

  stdHolder myHolder;

  // the following works
  std::vector<int> localSV = myHolder.getSV();
  for (std::vector<int>::iterator it = localSV.begin(); it != localSV.end(); it++ ) {
    std::cout << "printing " << *it + 100 << std::endl;
  }

  //return 0; // comment this line to see my problem

  // the following loops forever
  for (std::vector<int>::iterator it = myHolder.getSV().begin(); it != myHolder.getSV().end(); it++ ) {
    std::cout << "                                 printing " << *it + 100 << std::endl;
  }

  return 0;
C++ 标准向量

评论

8赞 user12002570 9/30/2022
myHolder.getSV().begin()并在不同的向量上工作。myHolder.getSV().end()
4赞 UnholySheep 9/30/2022
getSV()返回一个副本 - 因此每次调用此函数时都会获得一个新的向量。更改返回类型以查看其正常工作std::vector<int>&
0赞 Ted Lyngmo 9/30/2022
或者将 和 成员函数添加到 中。begin()end()stdHolder
0赞 Mgetz 9/30/2022
通常,永远不要在循环的条件部分调用,在设置中缓存一次结果。函数调用开销并非微不足道,该标准要求它假设您每次都使迭代器无效,因此它无法修复该性能错误。.end()
0赞 Ted Lyngmo 9/30/2022
然而,@Mgetz优化可能会注意到,没有什么会使迭代器失效,然后它仍然可以缓存它。哦,好吧,回避... :-)end()

答:

3赞 user12002570 9/30/2022 #1

我的问题(“为什么它不起作用?

因为和处理不同的向量,因为你要调用成员函数两次,并且每次调用都会返回一个不同的向量(因为你按值返回一个向量)。myHolder.getSV().begin()myHolder.getSV().end()stdHolder::getSV()

也就是说,迭代器是用 初始化的,但随后您正在比较(双关语),其结果是迭代器与调用返回的完全不同的向量。itmyHolder.getSV().begin()itmyHolder.getSV().end()myHolder.getSV()


解决此问题的一种方法是通过常量引用返回向量。这样,第一个循环将从返回值复制,而第二个循环将正常工作,因为它将从相同的向量数据成员中获取迭代器。请注意,如果您使用它,那么对于第二个循环,您必须制作一个 .itconst_iterator

请参阅以下修改程序中的注释:

class stdHolder {

public:

  stdHolder();
//-----------------------v---------------------------------->return by const lvalue reference
  const std::vector<int> &getSV() const {return _myVector;}

private:

  std::vector<int> _myVector;

};

stdHolder::stdHolder() {

  _myVector.push_back(1);
  _myVector.push_back(2);
  _myVector.push_back(3);

}

int main() {

  stdHolder myHolder;

  //still works 
  std::vector<int> localSV = myHolder.getSV();
  for (std::vector<int>::iterator it = localSV.begin(); it != localSV.end(); it++ ) {
    std::cout << "printing " << *it + 100 << std::endl;
  }

  //this works too now
  //---------------------vvvvvvvvvvvvvv--------------------------------------->const_iterator used instead of iterator
  for (std::vector<int>::const_iterator it = myHolder.getSV().begin(); it != myHolder.getSV().end(); it++ ) {
    std::cout << "                                 printing " << *it + 100 << std::endl;
  }

  return 0;
}

另一个选择是只为你添加和成员函数,然后你就可以使用基于范围的for循环beginendstdHolder

评论

0赞 ShadowRanger 9/30/2022
一个合理的解决方法可能是通过引用返回。第一个循环将从该返回值复制,而后一个循环是可以的,因为它会让迭代器脱离对同一基础的相同引用。 不是必需的,但它可以防止在界面上打孔,从而允许用户任意修改私有成员。getSVconstvectorconst
0赞 user12002570 9/30/2022
@ShadowRanger 是的,但请注意,对于第二个循环,then 应更改为 .只是在OP不知道这一点的情况下提及。itconst_iterator
0赞 ShadowRanger 9/30/2022
确定。虽然基本上是为了避免声明特定的迭代器类型而引起的恶化,所以除非你以某种方式被限制在 C++ 11 之前(如果是这样,我很可怜你),这不是你通常需要担心的事情。(当然,在这种情况下,普通的 for-each 样式循环也可以消除这种头痛)auto
0赞 user12002570 9/30/2022
@ShadowRanger是的,其他选项是添加和成员函数。beginend
1赞 troppapolvere 9/30/2022
我今天学到了一些东西!:-)