直接传递容器与传递容器引用的差异及set迭代器异常问题
C++容器传值与传引用的区别及std::set迭代器问题解析
1. 直接传递容器与引用传递容器的区别
- 内存开销与性能:直接传值会创建容器的完整副本,所有元素都会被复制,容器越大、元素越复杂,开销越高;引用传递只是传递容器的内存地址,没有复制操作,性能更优。
- 修改影响范围:传值时函数内修改的是副本,原容器不会有任何变化;非const引用传递时,函数内对容器的修改会直接作用于原容器。
- 迭代器有效性:传值得到的副本是独立容器,原容器的迭代器无法和副本的迭代器(包括
end())做有效比较;引用传递则始终指向原容器,迭代器的比较逻辑完全有效。
2. std::set传值导致无限输出的原因
两段代码的核心差异就是第二个参数的传递方式:一个是传值std::set<int> s,一个是传引用std::set<int>& s,问题出在迭代器和容器的绑定关系上。
传值版本的问题分析
- 调用
f(s.begin(), s)时,itr是原set的起始迭代器,而函数参数s是原set的全新副本,和原容器完全独立。 - 函数内判断
itr != s.end()时,s.end()是副本set的尾迭代器,但itr属于原容器,两者分属不同实例,这个比较的结果是未定义行为——实际运行中会一直返回true,永远不会触发退出条件。 - 随着递归调用,
itr不断自增,当走到原set的尾迭代器之后,继续自增会进入内存的未定义区域,输出垃圾数值,形成无限序列。
传引用版本的正常逻辑
- 调用
f(s.begin(), s)时,s是原set的引用,和itr属于同一个容器实例。 itr != s.end()的比较是同一容器内迭代器的有效比较,当itr走到原set的尾迭代器时,条件不成立,递归终止。- 因为std::set是有序容器,元素会自动排序为
-8,1,2,3,7,所以输出序列是-81237。
内容的提问来源于stack exchange,提问作者ilsec
相关产品推荐
相关产品推荐

