映射的c++映射错误,可能与分配器有关
c++ map of maps error, probably concerns allocators
这与我在这里问的这个问题有关:c++:通过从映射向量中分配映射实例来填充映射,但尚未解决。。。
代码都在那里提供。。错误消息(这里更新了我忘记报告的错误的第一个重要部分)是:
Program received signal SIGSEGV, Segmentation fault.
0x0804f9d4 in __gnu_cxx::new_allocator<std::pair<char* const, int> >::construct (this=0xbffff06f, __p=0x8057428, __val=...)
at /usr/include/c++/4.6/ext/new_allocator.h:108
108 { ::new((void *)__p) _Tp(__val); }
(gdb) backtrace
#0 0x0804f9d4 in __gnu_cxx::new_allocator<std::pair<char* const, int> >::construct (this=0xbffff06f, __p=0x8057428, __val=...)
at /usr/include/c++/4.6/ext/new_allocator.h:108
#1 0x0804f38e in std::_Rb_tree<char*, std::pair<char* const, int>, std::_Select1st<std::pair<char* const, int> >, std::less<char*>, std::allocator<std::pair<char* const, int> > >::_M_create_node (this=0x8098d1c, __x=...) at /usr/include/c++/4.6/bits/stl_tree.h:381
#2 0x0804e209 in std::_Rb_tree<char*, std::pair<char* const, int>, std::_Select1st<std::pair<char* const, int> >, std::less<char*>, std::allocator<std::pair<char* const, int> > >::_M_clone_node (this=0x8098d1c, __x=0xfffffffd) at /usr/include/c++/4.6/bits/stl_tree.h:427
#3 0x0804c5e5 in std::_Rb_tree<char*, std::pair<char* const, int>, std::_Select1st<std::pair<char* const, int> >, std::less<char*>, std::allocator<std::pair<char* const, int> > >::_M_copy (this=0x8098d1c, __x=0xfffffffd, __p=0x8098d20) at /usr/include/c++/4.6/bits/stl_tree.h:1036
#4 0x0804bd45 in std::_Rb_tree<char*, std::pair<char* const, int>, std::_Select1st<std::pair<char* const, int> >, std::less<char*>, std::allocator<std::pair<char* const, int> > >::operator= (this=0x8098d1c, __x=...) at /usr/include/c++/4.6/bits/stl_tree.h:945
#5 0x0804a6bc in std::map<char*, int, std::less<char*>, std::allocator<std::pair<char* const, int> > >::operator= (this=0x8098d1c, __x=...)
at /usr/include/c++/4.6/bits/stl_map.h:255
#6 0x080493d3 in MyProg::classify (trainData=..., testsData=...) at my_prog.cpp:78
#7 0x08049c46 in main () at my_prog.cpp:193
我在那篇链接的帖子中标出了确切的错误点。有人能指出这个错误的由来吗。
ps。它与分配器有什么关系?另外,我不想为分配器而烦恼,除非它在这里是绝对必要的。
编辑:这是代码(从上面的链接复制而来)笔记<--
标记错误点
InnerMap inmap;
vector<InnerMap> vec_inmap;
vec_inmap.resize (8);
int vec_inmap_sz = 8;
vec_inmap.insert (vec_inmap.end (), 8, inmap);
vector<InnerMap>::iterator vec_inmap_it = vec_inmap.begin ();
InnerMap::iterator inmap_it;
MiddlMap mdmap, curr_mdmap;
vector<MiddlMap> vec_mdmap;
vec_mdmap.resize (8);
int vec_mdmap_sz = 8;
vec_mdmap.insert (vec_mdmap.end (), 8, mdmap);
vector<MiddlMap>::iterator vec_mdmap_it = vec_mdmap.begin ();
MiddlMap::iterator mdmap_it;
OuterMap otmap;
OuterMap::iterator otmap_it;
即,我将inmap
和mdmap
的(空)副本存储在各自的向量中(问:这些副本是通过引用的吗?),然后稍后通过各自的向量迭代器从向量中提取这些副本,然后相应地填充映射。方法如下:
for (i = 0; i != trainSize; i++) {
...
if (curr_key_otmap != int_key) {
otmap[int_key] = *vec_mdmap_it;
vec_mdmap_it++;
mdmap_count++;
if (mdmap_count == vec_mdmap_sz) {
vec_mdmap_sz += 8;
vec_mdmap.resize (vec_mdmap_sz);
vec_mdmap.insert (vec_mdmap.end(), 8, mdmap);
}
curr_key_otmap = int_key;
curr_mdmap = otmap[curr_key_otmap];
}
mdmap_it = curr_mdmap.find (int_val);
if (mdmap_it == curr_mdmap.end ()) {
curr_mdmap[int_val] = *vec_inmap_it; <--
curr_mdmap[int_val][char_str] = 1;
vec_inmap_it++;
inmap_count++;
if (inmap_count == vec_inmap_sz) {
vec_inmap_sz += 8;
vec_inmap.resize (vec_inmap_sz);
vec_inmap.insert (vec_inmap.end(), 8, inmap);
}
} else {
inmap_it = (*mdmap_it).second.find (char_str);
if (inmap_it == (*mdmap_it).second.end ()) {
(*mdmap_it).second[char_str] = 1;
} else {
(*mdmap_it).second[char_str] += 1;
}
}
...
} //for ends
laune完全正确:迭代器在调用resize
或insert
后无效,可能不再使用。
除了laune的答案之外,在调用resize
之后,您不需要使用向量的insert
函数插入元素,因为resize
在容器的末尾添加了所需数量的元素。所以如果你写
vec_mdmap_sz += 8;
vec_mdmap.resize (vec_mdmap_sz);
vec_mdmap.insert (vec_mdmap.end(), 8, mdmap);
前两行添加额外的8个元素,最后一行再次插入8个元素。因此,您的容器大小总共增加了16个。你可以使用
vec_mdmap_sz += 8;
vec_mdmap.resize (vec_mdmap_sz, mdmap);
而是将您的容器增加8。但是,由于mdmap
是默认初始化的(使用默认构造函数),您可以将mdmap
参数删除到resize
函数中,因为resize
将默认初始化的元素添加到容器中(如果参数类型不提供默认构造函数,则仅使用size参数调用resize
将不会编译)。
作为另一个提示,您应该在迭代器上使用前缀增量运算符:而不是编写
vec_mdmap_it++;
只需使用
++vec_mdmap_it;
后缀迭代器复制迭代器的当前状态,增加迭代器并返回旧状态。因此后缀操作符必须执行复制操作。前缀运算符只是增加迭代器并返回对其自身的引用;因此不需要复制操作,因此前缀运算符更快。
在该代码中,您可以不断增加
vec_inmap_it++;
同时重新分配矢量
vec_inmap.resize (vec_inmap_sz);
它是从前面获得的。不要这样做——迭代器可能取决于某个容器的当前位置,并且在重新分配后不再有效。
如果您只是简单地使用索引并通过索引访问向量,那么一切都应该很好。
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 将函数类成员映射到类本身内部
- 如何在 C# 中映射双 C 结构指针?
- 如何在C++中使用结构生成映射
- 使用std::函数映射对象方法
- 如何加载(或映射)文件部分的最大大小,但适合在Windows上的RAM
- C++映射分割错误(核心转储)
- 内联映射初始化的动态atexit析构函数崩溃
- 使用"std::unordereded_map"映射到"std::list"对象
- 如何从多映射中删除特定的重复项
- 在未初始化映射的情况下,将值插入到映射的映射中
- 使用分配器对哈希映射进行高效的序列化和反序列化
- 映射的c++映射错误,可能与分配器有关
- 标准::映射的自定义分配器失败
- STL映射的自定义内存分配器
- 要使用 boost::object_pool 实现映射的自定义分配器,如何使用 boost::object_pool 分
- std::映射标准分配器性能与块分配器
- std::映射绑定到所有键和值的堆的分配器
- 正在使std::映射分配器工作