我有以下代码片段,它从查询游标中积累 BSON 文档,然后进行处理:
// Accumulate
std::vector<BSONObj> results;
while (cursor->more()) {
BSONObj r = cursor->nextSafe();
results.push_back(r);
}
...
// Process it (example)
for (unsigned int ix = 0; ix < results.size(); ix++) {
BSONElement be = results[ix].getField("_id");
// Do somtething with 'be'
...
}
此代码从一段时间(几个月)开始运行良好,但我们最近发现,对于数据库中的大型文档(大约 1.1MB),results[ix].getField("_id")
语句因段错误而崩溃。这是回溯的顶部:
(gdb) bt
#0 readNative<int> (offset=0, t=<synthetic pointer>, this=<optimized out>) at src/mongo/base/data_view.h:46
#1 readNative<int> (offset=0, this=<optimized out>) at src/mongo/base/data_view.h:53
#2 readLE<int> (offset=0, this=<optimized out>) at src/mongo/base/data_view.h:59
#3 objsize (this=0x7f74340022e0) at src/mongo/bson/bsonobj.h:309
#4 BSONObjIterator (jso=..., this=<synthetic pointer>) at src/mongo/bson/bsonobjiterator.h:42
#5 mongo::BSONObj::getField (this=0x7f74340022e0, name=...) at src/mongo/bson/bsonobj.cpp:635
...
我已经使用 results.push_back(r.copy())
而不是 results.push_back(r)
解决了这个问题。因此,错误可能是 r
对象在 while
block 作用域的末尾被销毁时引起的,从而使在 vector 中推回的拷贝处于不稳定状态。推回 r
的拷贝而不作为新变量进入 block 作用域似乎可以解决问题。
所以,我有以下问题:
将查询结果中的 BSONObj 存储在
std::vector
中的最佳方式是什么?我想我找到了一个合理的解决方案,但不确定这是否是最好的。为什么使用
push_back(r)
的代码适用于小文档?如果正确的方法是使用r.copy()
来避免在while
block 范围末尾破坏r
的问题,我理解它应该总是失败,不仅仅是在大约 1.1MB 的对象的情况下。
我正在使用 MongoDB C++ 驱动程序 legacy-1.0.7(如果它可能有帮助,或者问题可能与特定版本的 MongoDB C++ 驱动程序有关)。
最佳答案
nextSafe 返回的 BSONObj 对象不拥有它们的数据,并且会在后续调用 nextSafe 时失效。
因此,您的 vector 中填充了无效的 BSONObj 对象。
相反,在推回 vector 之前对游标结果调用 BSONObj::getOwned()。
如果您在 AddressSanitizer 或 valgrind 下运行您的程序,您几乎肯定会看到释放后使用类型错误。
关于c++ - 在 std::vector 中存储 BSONObj 对象会因大文档而崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36998896/