c++ - 在 std::vector 中存储 BSONObj 对象会因大文档而崩溃

标签 c++ mongodb stdvector

我有以下代码片段,它从查询游标中积累 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 作用域似乎可以解决问题。

所以,我有以下问题:

  1. 将查询结果中的 BSONObj 存储在 std::vector 中的最佳方式是什么?我想我找到了一个合理的解决方案,但不确定这是否是最好的。

  2. 为什么使用 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/

相关文章:

c++ - 需要 dll 入口点问题/建议

c++ - 为什么结构大小与项目大小的简单总和不匹配?

c++ - FindBLAS 和 FindLAPACK 在 CMake 中的使用

C++ 使用 ofstream 写入二进制文件

c++ - 将瓦片 map 解析为高效的水平和垂直边界框

java - 配置 MongoDB 写入关注超时?

c# - 具有非空字段的 Mongo C# 驱动程序上的聚合不过滤

mongodb - mongodb 中的预读代表什么?

c++ - 如何在 C 函数中使用 std::vector

c++ - C++ std::vector 的两个指针替代方案