std vector如何避免頻繁內(nèi)存創(chuàng)建

1. std vector中添加元素

In C++ vectors are dynamic arrays. Unlike arrays, they don’t have a fixed size. They can grow or shrink as required. Vectors are assigned memory in blocks of contiguous locations. When the memory allocated for the vector falls short of storing new elements, a new memory block is allocated to vector and all elements are copied from the old location to the new location. This reallocation of elements helps vectors to grow when required. However, it is a costly operation and time complexity is involved in this step is linear.

vector內(nèi)存不足的時(shí)候,會(huì)重新分配內(nèi)存block,而且會(huì)把之前已有的數(shù)據(jù)拷貝到新的內(nèi)存。這一系列操作是一個(gè)稍微耗時(shí)的操作,下面通過(guò)實(shí)際的例子說(shuō)明,

#include <iostream>
#include <vector>


class A {
public:
    A(int i) :i_(i) { std::cout << "ptr: [" << this << " ]" << " default ctor" << " i_= " << i_ << std::endl; }
    A(const A& x) {
        std::cout << "ptr: [" << this << " ]" << " copy ctor" << " i_= " << x.i_ << std::endl;
        i_ = x.i_;
    }
    ~A() {
        std::cout << "ptr: [" << this << " ]" << " dector" << " i_= " << i_ << std::endl;
    }
private:
    int i_;
};

int main() {
    std::vector<A> y;
    std::cout << "y.size()= " << y.size() << std::endl;
    //先生成A(1)臨時(shí)對(duì)象,然后在std::vector<A>中的構(gòu)造(拷貝構(gòu)造函數(shù)),然后A(1)臨時(shí)對(duì)象析構(gòu)
    y.push_back(A(1));
    std::cout << "y.size()= " << y.size() << std::endl;
    y.push_back(A(2));
    std::cout << "y.size()= " << y.size() << std::endl;
    y.push_back(A(3));
    std::cout << "y.size()= " << y.size() << std::endl;
    return 0;
};

程序輸出的結(jié)果,

y.size()= 0
ptr: [0000000B4D58FB74 ] default ctor i_= 1
ptr: [00000116C1FC0850 ] copy ctor i_= 1
ptr: [0000000B4D58FB74 ] dector i_= 1
y.size()= 1
ptr: [0000000B4D58FB78 ] default ctor i_= 2
ptr: [00000116C1FD1A14 ] copy ctor i_= 2
//00000116C1FC0850 又被拷貝到了 00000116C1FD1A10,之前的00000116C1FC0850又析構(gòu)
ptr: [00000116C1FD1A10 ] copy ctor i_= 1
ptr: [00000116C1FC0850 ] dector i_= 1
ptr: [0000000B4D58FB78 ] dector i_= 2
y.size()= 2
ptr: [0000000B4D58FB7C ] default ctor i_= 3
ptr: [00000116C1FD1BF8 ] copy ctor i_= 3
ptr: [00000116C1FD1BF0 ] copy ctor i_= 1
ptr: [00000116C1FD1BF4 ] copy ctor i_= 2
ptr: [00000116C1FD1A10 ] dector i_= 1
ptr: [00000116C1FD1A14 ] dector i_= 2
ptr: [0000000B4D58FB7C ] dector i_= 3
y.size()= 3
ptr: [00000116C1FD1BF0 ] dector i_= 1
ptr: [00000116C1FD1BF4 ] dector i_= 2
ptr: [00000116C1FD1BF8 ] dector i_= 3

從上面的結(jié)果我們能看出來(lái),

  1. 調(diào)用vectorpush_back(),先生成A(1)臨時(shí)對(duì)象,然后在std::vector<A>中的構(gòu)造(拷貝構(gòu)造函數(shù)),然后A(1)臨時(shí)對(duì)象析構(gòu);
  2. 當(dāng)牽扯到內(nèi)存重新分配的時(shí)候,確實(shí)會(huì)把std::vector<A>中已有的元素重新復(fù)制到新的內(nèi)存,例如結(jié)果中的多次調(diào)用拷貝構(gòu)造函數(shù)(copy ctor i_= 1)。

2. std move

在c++11中,標(biāo)準(zhǔn)庫(kù)新加了std::move,即移動(dòng)語(yǔ)義,它的一個(gè)作用是減少對(duì)象拷貝的開銷,具體少了多少?zèng)]細(xì)研究,這里僅貼出來(lái)代碼。

#include <iostream>
#include <vector>


class A {
public:
    A(int i) :i_(i) { std::cout << "ptr: [" << this << " ]" << " default ctor" << " i_= " << i_ << std::endl; }
    A(const A& x) {
        std::cout << "ptr: [" << this << " ]" << " copy ctor" << " i_= " << x.i_ << std::endl;
        i_ = x.i_;
    }
    A(const A&& x)noexcept {
        std::cout << "ptr: [" << this << " ]" << " move ctor" << " i_= " << x.i_ << std::endl;
        i_ = x.i_;
    }
    ~A() {
        std::cout << "ptr: [" << this << " ]" << " dector" << " i_= " << i_ << std::endl;
    }
private:
    int i_;
};

int main() {
    std::vector<A> y;
    //y.reserve(10);
    std::cout << "y.size()= " << y.size() << std::endl;
    y.push_back(std::move(A(1)));
    std::cout << "y.size()= " << y.size() << std::endl;
    y.push_back(std::move(A(2)));
    std::cout << "y.size()= " << y.size() << std::endl;
    y.push_back(std::move(A(3)));
    std::cout << "y.size()= " << y.size() << std::endl;
    return 0;
};

輸出結(jié)果如下,

y.size()= 0
ptr: [00000080C32FF914 ] default ctor i_= 1
ptr: [000001FA06440850 ] move ctor i_= 1
ptr: [00000080C32FF914 ] dector i_= 1
y.size()= 1
ptr: [00000080C32FF918 ] default ctor i_= 2
ptr: [000001FA06451A04 ] move ctor i_= 2
ptr: [000001FA06451A00 ] move ctor i_= 1
ptr: [000001FA06440850 ] dector i_= 1
ptr: [00000080C32FF918 ] dector i_= 2
y.size()= 2
ptr: [00000080C32FF91C ] default ctor i_= 3
ptr: [000001FA06451968 ] move ctor i_= 3
ptr: [000001FA06451960 ] move ctor i_= 1
ptr: [000001FA06451964 ] move ctor i_= 2
ptr: [000001FA06451A00 ] dector i_= 1
ptr: [000001FA06451A04 ] dector i_= 2
ptr: [00000080C32FF91C ] dector i_= 3
y.size()= 3
ptr: [000001FA06451960 ] dector i_= 1
ptr: [000001FA06451964 ] dector i_= 2
ptr: [000001FA06451968 ] dector i_= 3

和1中的輸出結(jié)果類似,依然會(huì)牽扯內(nèi)存的移動(dòng)(前面是拷貝)。

3. 如何解決這個(gè)問(wèn)題

std::vector class provides a useful function reserve which helps user specify the minimum size of the vector.It indicates that the vector is created such that it can store at least the number of the specified elements without having to reallocate memory.

可以利用reserve()函數(shù)告訴系統(tǒng)最少準(zhǔn)備多少內(nèi)存,就不用來(lái)回分配內(nèi)存,多次創(chuàng)建、析構(gòu)了,如下所示,

#include <iostream>
#include <vector>


class A {
public:
    A(int i) :i_(i) { std::cout << "ptr: [" << this << " ]" << " default ctor" << " i_= " << i_ << std::endl; }
    A(const A& x) {
        std::cout << "ptr: [" << this << " ]" << " copy ctor" << " i_= " << x.i_ << std::endl;
        i_ = x.i_;
    }
    A(const A&& x)noexcept {
        std::cout << "ptr: [" << this << " ]" << " move ctor" << " i_= " << x.i_ << std::endl;
        i_ = x.i_;
    }
    ~A() {
        std::cout << "ptr: [" << this << " ]" << " dector" << " i_= " << i_ << std::endl;
    }
private:
    int i_;
};

int main() {
    std::vector<A> y;
    //預(yù)留10的空間
    y.reserve(10);
    std::cout << "y.size()= " << y.size() << std::endl;
    y.push_back(std::move(A(1)));
    std::cout << "y.size()= " << y.size() << std::endl;
    y.push_back(std::move(A(2)));
    std::cout << "y.size()= " << y.size() << std::endl;
    y.push_back(std::move(A(3)));
    std::cout << "y.size()= " << y.size() << std::endl;
    return 0;
};

輸出結(jié)果如下,少了很多多余的操作。

y.size()= 0
ptr: [000000954C4FF614 ] default ctor i_= 1
ptr: [00000291C41050A0 ] move ctor i_= 1
ptr: [000000954C4FF614 ] dector i_= 1
y.size()= 1
ptr: [000000954C4FF618 ] default ctor i_= 2
ptr: [00000291C41050A4 ] move ctor i_= 2
ptr: [000000954C4FF618 ] dector i_= 2
y.size()= 2
ptr: [000000954C4FF61C ] default ctor i_= 3
ptr: [00000291C41050A8 ] move ctor i_= 3
ptr: [000000954C4FF61C ] dector i_= 3
y.size()= 3
ptr: [00000291C41050A0 ] dector i_= 1
ptr: [00000291C41050A4 ] dector i_= 2
ptr: [00000291C41050A8 ] dector i_= 3
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容