vector内存分配简单介绍

众所周知,vector的size()其实并不代表它占用的空间,它实际占用空间可以用capacity()查看

众所周知,push_back()时,如果size==capacity则会使capacity从0变1或者变为原来两倍,当然如果size<capacity则不会触发内存分配

众(gui)所(cai)周(zhi)知(dao),一旦触发内存分配,原来的指针或者迭代器失效,因为vector的所有内容搬迁到新的内存里了

你可能觉得push_back()奇慢无比,那倒也不至于,因为平均下来push_back()复杂度确实是 \(O(1)\)

当然慢也是有一定道理的,因为如果直接用vector数组作为邻接表来存图,效率并不理想

比如我们定义了 vector<int> a[100010];,随机建边的时候就会疯狂触发内存分配导致愉快地tle(不过图论题这么毒瘤的也不常见)

解决方法是前向星或者手写分配器。如果不手写分配器用list替代vector貌似更慢了(虽然我也不知道为什么,另外forward_list和vector差不多的亚子)

众(gui)所(cai)周(zhi)知(dao),不止push_back(),像resize(),reserve()等都会触发内存分配

众(gui)所(cai)周(zhi)知(dao),像clear(),pop_back()等并不会释放内存(也就不会使capacity变小),只有shrink_to_fit()等少数几个操作才能使capacity变小。因此有些不得已的情况会用a=vector<int>()来代替a.clear()

当然也有可能a.clear()导致mle,a=vector<int>()导致tle(笑)

众(gui)所(cai)周(zhi)知(dao),vector对内存分配的惰性其实是为了效率考虑的,它很好地规避了频繁的分配释放空间。vector满足了很多常见需求。但是像图论等某些地方还是不能偷懒,还得花点功夫写分配器,或者用前向星、手写queue这种朴素方法代替stl

手写分配器的方法如下:

static char space[10000000],*sp=space;
template<typename T>
struct allc:allocator<T>{
    allc(){}
    template<typename U>
    allc(const allc<U> &a){}
    template<typename U>
    allc<T>& operator=(const allc<U> &a){return *this;}
    template<typename U>
    struct rebind{typedef allc<U> other;};
    inline T* allocate(size_t n){
        T *res=(T*)sp;
        sp+=n*sizeof(T);
        return res;
    }
    inline void deallocate(T* p,size_t n){}
};
vector< int,allc<int> > a;

猜你喜欢

转载自www.cnblogs.com/axiomofchoice/p/12366920.html