[英]Using for auto in nested loops
美好的一天,我最近一直在尝试转向 C++ 以加速我的一些应用程序。 可能是由于缺乏背景知识,我犯了这样一个愚蠢的错误,但是,在尝试使用嵌套循环运行它时,我interrupted by signal 11: SIGSEGV
:
mongocxx::cursor cursor = coll.find({});
for(auto doc : cursor) {
std::cout << "TEST FIRST" << bsoncxx::to_json(doc) << "\n";
for (auto doc2 : cursor) {
std::cout << "FIRST: " << bsoncxx::to_json(doc) << "\n";
std::cout << "SECOND: " << bsoncxx::to_json(doc2) << "\n";
} }
我到底做错了什么,为什么?
您代码中的问题是您在两个循环中都在cursor
上迭代,但是来自mongocxx
文档:
[...] 取消引用任何非 end() 迭代器总是会给出游标中的第一个剩余文档。 增加一个非结束迭代器相当于增加所有迭代器。
和
[...] 如果 begin() 被多次调用,cursor::iterator 返回的指向下一个剩余的结果,而不是对 begin() 的原始调用的结果。
在 C++ 中,范围循环只是使用迭代器的一种隐藏方式,问题在于(根据上面的引用),当您增加内循环迭代器时,实际上是在增加外循环迭代器。 您的代码(大约)相当于:
for (auto it = cursor.begin(); it != cursor.end(); ++it) {
// there may or may not be a ++it here, that does not change the explanation
// but the documentation of mongocxx is unclear on this
for (++it; it != cursor.end(); ++it) { }
}
问题是,当内循环到达cursor.end()
,你在外循环中增加it
,然后再次将它与cursor.end()
进行比较,这可能就是你得到SIGSEV
。
做你想做的唯一方法是要么有两个游标,要么把所有东西都存储在一个容器中(例如,一个std::vector
),然后迭代这个向量(你不会遇到与std::vector
相同的问题) std::vector
)。
关于评论中提到的const&
的旁注 - 当您执行for(auto doc: cursor)
,这等效于(不完全是,但您会明白):
for (auto it = cursor.begin(); it != cursor.end(); ++i) {
auto doc = *it; // here, you make a copy of *it, this is expensive
}
用const auto&
替换auto
改变了doc
的声明,并使它成为对迭代器指向的值的引用。
除了我上面提到的其他问题,这会给你不正确的结果,因为当你在内循环中迭代时,你实际上也在增加外循环迭代器,所以外循环doc
引用要么指向某些东西不再存在(UB)或指向新迭代器的底层对象,实际上是doc2
,因此您将拥有&doc == &doc2
,即doc
和doc2
都将指向同一个对象(同时具有const auto&
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.