VS2015中使用Berkeley DB STL的dbstl::db_map<string, list<string>>报错解决
在Visual Studio 2015环境下使用Berkeley DB STL库,尝试将list<string>作为dbstl::db_map的value类型时运行报错,触发“list iterator not dereferencable”等断言失败问题,以下是代码、错误详情及解决方案:
问题代码
#define _CRT_SECURE_NO_WARNINGS #pragma comment(lib, "libdb181.lib") #pragma comment(lib, "libdb_stl181.lib") #include "stdafx.h" #include <iostream> #include <dbstl_map.h> #include <list> using namespace std; int main(){ const char* db_name = "db"; const char* db_home_dir = "dbdir"; DbEnv env(DB_CXX_NO_EXCEPTIONS); Db* pdb; try { dbstl::dbstl_startup(); env.set_error_stream(&cerr); env.open(db_home_dir, DB_CREATE | DB_INIT_MPOOL, 0); pdb = new Db(&env, DB_CXX_NO_EXCEPTIONS); pdb->open(NULL, db_name, NULL, DB_BTREE, DB_CREATE, 0); typedef dbstl::db_map<string, list<string>> dbmap_list; dbmap_list map_list(pdb, &env); string key_list = "list"; list<string> value_list; value_list.push_back("first"); value_list.push_back("second"); map_list.insert({ key_list, value_list }); list<string> outvalue_list = map_list[key_list]; list<string>::iterator it = outvalue_list.begin(); cout << *it; dbstl::dbstl_exit(); if (pdb != NULL) { pdb->close(0); delete pdb; } env.close(0); } catch (DbException& e) { cerr << "DbException: " << e.what() << endl; _sleep(5000); return -1; } catch (std::exception& e) { cerr << e.what() << endl; _sleep(5000); return -1; } cout << "hello"; _sleep(5000); return 0; }
错误信息
程序: C:\Windows\SYSTEM32\MSVCP140D.dll
文件: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\list
行: 211
表达式: list iterator not dereferencable
有关程序如何导致断言失败的信息,请查看 Visual C++ 文档中的断言说明。
(按重试调试应用程序) ConsoleApplication8.exe 触发了断点。
调试断言失败!
程序: ..._V36\p1\ConsoleApplication8\x64\Debug\ConsoleApplication8.exe
文件: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\list
行: 212
表达式: "Standard C++ Libraries Out of Range" && 0
有关程序如何导致断言失败的信息,请查看 Visual C++ 文档中的断言说明。
(按重试调试应用程序)
'ConsoleApplication8.exe' (Win32): 已加载 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\14.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll'。
'ConsoleApplication8.exe' (Win32): 已卸载 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\14.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll'
'ConsoleApplication8.exe' (CLR v4.0.30319: ConsoleApplication8.exe): 已加载 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\14.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll'。
在 ConsoleApplication8.exe 中的 0x00007FFB60CF10CB (ucrtbased.dll) 处发生未处理的异常: 传递给考虑无效参数为致命错误的函数的参数无效。
原因及解决方法
问题根源
DBSTL的默认序列化机制对std::list的支持存在缺陷:std::list是链表结构,其迭代器依赖内部节点的内存地址,反序列化后链表的节点地址发生变化,导致迭代器失效;同时默认序列化可能未正确还原std::list的内部状态,读取后得到空链表,进而触发“迭代器不可解引用”的断言。
方案1:改用std::vector替代std::list
std::vector是连续内存结构,DBSTL的默认序列化逻辑能正确处理其内存布局,不会出现迭代器失效问题。修改代码如下:
// 替换list为vector typedef dbstl::db_map<string, vector<string>> dbmap_list; // 对应value类型也修改 vector<string> value_list; value_list.push_back("first"); value_list.push_back("second"); map_list.insert({ key_list, value_list }); auto it_map = map_list.find(key_list); if (it_map != map_list.end()) { vector<string> outvalue_list = it_map->second; if (!outvalue_list.empty()) { cout << outvalue_list[0]; } }
方案2:为std::list实现自定义序列化/反序列化
通过特化dbstl::db_serializer模板,手动实现std::list<string>的序列化和反序列化逻辑,确保数据正确存储和还原:
#include <cstring> namespace dbstl { template<> class db_serializer<list<string>> { public: static void serialize(const list<string>& obj, Dbt& dbt) { // 计算总字节数:每个字符串存长度(size_t)+ 内容 size_t total_size = 0; for (const auto& s : obj) { total_size += sizeof(size_t) + s.size(); } // 分配内存并写入数据 char* buf = new char[total_size]; char* ptr = buf; for (const auto& s : obj) { size_t len = s.size(); memcpy(ptr, &len, sizeof(len)); ptr += sizeof(len); memcpy(ptr, s.c_str(), len); ptr += len; } // 设置Dbt,让DB负责释放内存 dbt.set_data(buf); dbt.set_size(total_size); dbt.set_flags(DB_DBT_APPMALLOC); } static void deserialize(Dbt& dbt, list<string>& obj) { obj.clear(); char* ptr = static_cast<char*>(dbt.get_data()); size_t remaining = dbt.get_size(); // 逐个读取字符串 while (remaining > 0) { size_t len; memcpy(&len, ptr, sizeof(len)); ptr += sizeof(len); remaining -= sizeof(len); string s(ptr, len); obj.push_back(s); ptr += len; remaining -= len; } } }; }
额外注意事项
- 避免直接使用
map_list[key_list]:若key不存在,该操作会默认构造空的list<string>,增加出错风险。建议先用find检查key是否存在,再访问对应value。 - 确保Berkeley DB与DBSTL版本匹配:代码中使用的是18.1版本,需保证库文件
libdb181.lib、libdb_stl181.lib与头文件版本一致。
内容的提问来源于stack exchange,提问作者Ilya

