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)存不足的時候奶甘,會重新分配內(nèi)存block谬莹,而且會把之前已有的數(shù)據(jù)拷貝到新的內(nè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() {
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)臨時對象疑枯,然后在std::vector<A>中的構(gòu)造(拷貝構(gòu)造函數(shù))沦泌,然后A(1)臨時對象析構(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é)果我們能看出來包雀,
- 調(diào)用
vector
的push_back()
,先生成A(1)
臨時對象亲铡,然后在std::vector<A>
中的構(gòu)造(拷貝構(gòu)造函數(shù))才写,然后A(1)
臨時對象析構(gòu)葡兑; - 當(dāng)牽扯到內(nèi)存重新分配的時候,確實會把
std::vector<A>
中已有的元素重新復(fù)制到新的內(nèi)存赞草,例如結(jié)果中的多次調(diào)用拷貝構(gòu)造函數(shù)(copy ctor i_= 1
)讹堤。
2. std move
在c++11中,標準庫新加了std::move
厨疙,即移動語義洲守,它的一個作用是減少對象拷貝的開銷,具體少了多少沒細研究沾凄,這里僅貼出來代碼岖沛。
#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é)果類似搭独,依然會牽扯內(nèi)存的移動(前面是拷貝)婴削。
3. 如何解決這個問題
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)最少準備多少內(nè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