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),
- 調(diào)用
vector的push_back(),先生成A(1)臨時(shí)對(duì)象,然后在std::vector<A>中的構(gòu)造(拷貝構(gòu)造函數(shù)),然后A(1)臨時(shí)對(duì)象析構(gòu); - 當(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