两种遍历vector的方法结果不一致,原因是什么?
问题根源:临时容器导致的迭代器失效
兄弟,你这个问题根本不是遍历方式的锅——核心问题出在getSausageBox()的返回值和临时对象的生命周期上!
先拆解你的两段代码:
迭代器遍历的致命问题
看这段代码:
for(vector <NgramOutput*>::iterator sausage = (*sausageCarton)->getSausageBox().begin(); sausage != (*sausageCarton)->getSausageBox().end(); ++sausage){ dosomething(*sausage); }
如果getSausageBox()的返回类型是**vector<NgramOutput*>(值返回,而非引用)**,那每次调用这个函数都会生成一个全新的临时vector对象。
- 第一次调用
getSausageBox().begin()时,你拿到的是这个临时vector的起始迭代器,但这个临时对象在这条语句执行完就会被销毁,内存被释放。 - 到了循环条件判断时,你又调用了一次
getSausageBox().end(),这时候生成的是另一个完全独立的临时vector的结束迭代器。
这就导致你的sausage迭代器指向的是已经被销毁的内存,而且和循环判断里的end迭代器根本不属于同一个容器——循环逻辑彻底混乱,访问*sausage自然就是无效的垃圾数据。
下标遍历为啥没问题
再看这段:
for (int i=0; i < sausage.size(); i++) { dosomething(sausage[i]); }
这里的sausage应该是你提前用类似auto sausage = (*sausageCarton)->getSausageBox();的代码保存了一份容器拷贝,这个sausage是存在于栈上的有效对象,下标访问的是它的合法元素,所以结果完全符合预期。
解决办法
有两个靠谱的修复方向:
修改
getSausageBox()返回引用
把函数的返回类型改成引用,这样所有调用都会指向同一个原容器,不会生成临时对象:// 非const场景 vector<NgramOutput*>& getSausageBox(); // const对象调用的场景 const vector<NgramOutput*>& getSausageBox() const;这是最优解,避免不必要的拷贝,同时保证迭代器的有效性。
提前拷贝到局部变量
如果没办法修改getSausageBox()的定义,那就先把容器拷贝到局部变量,再用迭代器遍历:auto sausageBox = (*sausageCarton)->getSausageBox(); for(auto sausage = sausageBox.begin(); sausage != sausageBox.end(); ++sausage){ dosomething(*sausage); }
最后再强调下:迭代器和下标遍历本身是等价的(除了性能上的细微差异),你的问题完全是临时对象和迭代器生命周期不匹配导致的,和遍历方式无关~
内容的提问来源于stack exchange,提问作者Derek Seabrooke
相关产品推荐
相关产品推荐

