Memory management std::vector、std::map和内存问题

Memory management std::vector、std::map和内存问题,memory-management,stl,vector,map,Memory Management,Stl,Vector,Map,我正在编写将数据库中的行插入向量的代码。然后将向量存储在std::map中。这种体系结构允许我基于映射键对数据集(向量)进行逻辑分区 在我的代码中,我将从std::map中检索一个数据集(即向量),向其中添加/删除行或对其执行一些其他逻辑,然后将向量粘贴回map中(所有这些都在while()循环中进行) 我有两个问题,这两个问题都与向量中存储的(可能)大量元素有关。向量可以包含几十到几万个元素。我无法事先知道将从数据库中检索多少条记录。因此,std::vector的内存管理方案(即alloc/D

我正在编写将数据库中的行插入向量的代码。然后将向量存储在std::map中。这种体系结构允许我基于映射键对数据集(向量)进行逻辑分区

在我的代码中,我将从std::map中检索一个数据集(即向量),向其中添加/删除行或对其执行一些其他逻辑,然后将向量粘贴回map中(所有这些都在while()循环中进行)

我有两个问题,这两个问题都与向量中存储的(可能)大量元素有关。向量可以包含几十到几万个元素。我无法事先知道将从数据库中检索多少条记录。因此,std::vector的内存管理方案(即alloc/Dealoc)变得非常重要,以便有效地使用内存,并避免不必要的(内存)碎片:

我的问题是:

  • 考虑到一行可以存储的元素数量可能很大,理想情况下,我希望从内存池中alloc/dealloc。但我不知道如何将std::vector与内存池一起使用,我也不知道这是否会变得不必要的复杂。如果这是过度(或太复杂),那么我的另一个想法是在向量第一次创建时预先分配一个固定的内存板。但这也可能过于简单化,因为元素的数量可能因向量实例的不同而有很大差异,导致(内存)碎片等,更不用说内存的低效使用了

    这里推荐的方法是什么?

  • 鉴于std::map(所有STL容器IIRC)存储value元素的副本,制作包含数万个元素的向量副本的前景是完全错误的。因此,我想在stl::map周围编写一个SmartPointerMap包装器,然后存储指向向量的指针,而不是实际向量

    我走对了吗?。如果没有,什么是更好的解决方案。?。如果是,是否可以使用boost库(而不是编写SmartPointerMap类模板)?

  • [编辑]

    我正在使用GCC4.4.1构建Linux(Ubuntu 9.10)来回答问题2:

    using namespace std;
    
    map<string, vector<int>* > foo;
    vector<int>* pointer= foo["thekey"];
    
    使用名称空间std;
    map foo;
    向量*指针=foo[“thekey”];
    
    如果需要使用智能(引用计数)指针:

    #include<tr1/shared_ptr.h>
    using namespace std::tr1;
    using namespace std;
    
    map<string, shared_ptr<vector<int> > > foo;
    shared_ptr<vector<int> > pointer= foo["thekey"];
    
    #包括
    使用名称空间std::tr1;
    使用名称空间std;
    map foo;
    共享的指针=foo[“thekey”];
    
    为了回答问题#1,您可以编写一个新的分配器模板类并声明向量以使用该分配器,但我对编写分配器一无所知:

    map<string, vector<int, myallocator<int> >* > foo;
    
    map-foo;
    

    特别是,我不知道如何设计一个分配器来避免内存池的碎片化。(但如果您已回答了该部分,那么编写自定义分配器将是一种方法。)

    假设您对地图的
    数据类型使用
    矢量
    ,而不是
    键类型
    ,则可以在不复制数据的情况下就地修改数据
    std::map::operator[]()
    返回对非常量数据类型的引用,并且从非常量版本的
    std::map::find()
    返回的迭代器允许您修改数据

    如果在更改数据时需要更改密钥,该怎么办?您可以使用
    std::swap()
    将数据从一个向量移动到另一个向量,而无需复制

    不要忘记,当您擦除元素时,
    vector
    不会降低其
    容量()。另外,
    vector
    通常会分配比您需要的更多的
    capacity()
    ,因此
    push_back()
    需要摊销的固定时间。对于非常大的向量,如果不小心,这些行为可能会显著增加程序的内存使用

    如果您对地图的
    键类型使用
    向量
    ,并且地图的键非常大,那么指针或智能指针可能会有所帮助。但是,如果是这种情况,则必须确保不要修改其中一个映射值所指向的键的内容,因为
    std::map
    不是为处理该问题而设计的


    至于自定义分配器的想法,首先让您的代码使用标准分配器,然后看看它是否足够快。使用标准分配器可能没问题。如果您的代码在使用标准分配器时速度不够快,请配置文件以查看实际花费的时间(可能在其他地方,如数据库代码)。如果您编写了一个自定义分配器,并且从未将其与标准分配器进行比较,那么您将不知道您的自定义分配器是否真的是一种改进;它可能比标准的分配器慢得多。

    Wrt#1,GCC/Linux(ptmalloc)中的默认堆实现将为小对象使用一个空闲列表(又称内存池)(我将建议一种更通用的方法来处理C/C++中的数据库查询集

    执行db查询并将行放入结构数组中。如果没有足够的物理内存,请使用内存映射文件,该文件将返回指向结构数组底部的指针,处理器芯片上的MMU将在需要时担心这些结构会驻留在内存中

    现在,您可以在一个键上对这个结构数组进行排序(),这将为您提供ISAM访问,关系宗教中的异端邪说,但这正是游标给您的。这是数据访问方法#1

    现在,如果您仍然需要以另一种方式查看该数据,只需创建一个或多个索引/映射,其中映射的键是适当的(列值/结构成员)映射的数据值是指向该结构在内存映射文件中的位置的指针。这提供了与db索引完全相同的功能。通过struct.member值订阅映射