目录:
一、在std::vector尾部添加对象时应尽量使用emplace_back,而不要使用push_back
二、添加多个元素前应使用reserve设置容量,防止扩容时发生元素复制
六、需要将对象全部转移到另外一std::vector时,应使用std::vector.swap()、std::swap()、std::move(std::vector)
七、如果std::vector中在存放指针对象,即std::vector,则应使用智能指针
先说一下关于std::vector的一些基本知识:
- std::vector<T>中存放的T对象是在堆中分配的。
- std::vector<T>会负责管理T对象的生命周期,所以当将T对象存放到std::vector<T>中时,std::vector<T>会构造一个自己能完全控制的T对象,构造方式可以是转移构造函数、拷贝构造函数还是普通构造函数。
- 当std::vector<T>的生命周期结束时,std::vector<T>也同时会将其中存放的对象析构。
对于如何高效使用std::vector,以下有几点建议。先给出一个类的代码,后面会用到它:
class Girl {
public:
string name;
int age;
Girl() {
cout << "Girl()" << endl;
}
Girl(const string& _name, int _age) : name(_name), age(_age) {
cout << "Girl(string _name, int _age)" << name << endl;
}
Girl(const Girl& b) : name(b.name), age(b.age) {
cout << "Girl(const Girl&)" << name << endl;
}
Girl(Girl&& b) : name(move(b.name)), age(move(b.age)) {
cout << "Girl(Girl&&)" << name << endl;
}
Girl& operator=(const Girl& b) {
this->name = b.name;
this->age = b.age;
cout << "operator=(const Girl&)" << name << endl;
return *this;
}
~Girl() {
cout << "~Girl()" << name << endl;
}
};
一、在std::vector<T>尾部添加对象时应尽量使用emplace_back,而不要使用push_back
int main() {
vector<Girl> vvv1;
vector<Girl> vvv2;
cout << "------------------------------------------------" << endl;
vvv1.push_back(Girl("dd", 90));
cout << "------------------------------------------------" << endl;
vvv2.emplace_back("dd", 90);
cout << "------------------------------------------------" << endl;
return 1;
}
------------------------------------------------
Girl(string _name, int _age)dd
Girl(Girl&&)dd
~Girl()
------------------------------------------------
Girl(string _name, int _age)dd
------------------------------------------------
~Girl()dd
~Girl()dd
从结果中可以看到,使用push_back会比emplace_back多调了转移构造函数和析构函数,因而性能偏低。
二、添加多个元素前应使用reserve设置容量,防止扩容时发生元素复制
int main() {
vector<Girl> vvv1;
cout << vvv1.size() << endl;
cout << vvv1.capacity() << endl;
vvv1.emplace_back("ss", 12);
cout << "------------------------------------------------" << endl;
vvv1.emplace_back("xx", 33);
cout << "------------------------------------------------" << endl;
vvv1.emplace_back("wq", 123);
cout << "------------------------------------------------" << endl;
cout << vvv1.size() << endl;
cout << vvv1.capacity() << endl;
cout << "------------------------------------------------" << endl;
vector<Girl> vvv2;
vvv2.reserve(10);
cout << vvv2.size() << endl;
cout << vvv2.capacity() << endl;
vvv2.emplace_back("ss", 12);
cout << "------------------------------------------------" << endl;
vvv2.emplace_back("xx", 33);
cout << "------------------------------------------------" << endl;
vvv2.emplace_back("wq", 123);
cout << "------------------------------------------------" << endl;
cout << vvv2.size() << endl;
cout << vvv2.capacity() << endl;
cout << "------------------------------------------------" << endl;
return 1;
}
0
0
Girl(string _name, int _age)ss
------------------------------------------------
Girl(string _name, int _age)xx
Girl(const Girl&)ss
~Girl()ss
------------------------------------------------
Girl(string _name, int _age)wq
Girl(const Girl&)ss
Girl(const Girl&)xx
~Girl()ss
~Girl()xx
------------------------------------------------
3
3
------------------------------------------------
0
10
Girl(string _name, int _age)ss
------------------------------------------------
Girl(string _name, int _age)xx
------------------------------------------------
Girl(string _name, int _age)wq
------------------------------------------------
3
10
------------------------------------------------
~Girl()ss
~Girl()xx
~Girl()wq
~Girl()ss
~Girl()xx
~Girl()wq
从结果中可以看到,由于vvv1没有设置reserver,导致初始容量不足,每添加一个新的对象都要先扩容,然后将以前存放的对象复制过去,因而性能偏低。
三、删除元素时应从最后一个元素开始删除,不要从中间开始删除
int main() {
vector<Girl> vvv1;
vvv1.reserve(10);
vvv1.emplace_back("ss", 12);
vvv1.emplace_back("xx", 33);
vvv1.emplace_back("wq", 123);
cout << "------------------------------------------------" << endl;
vector<Girl> vvv2;
vvv2.reserve(10);
vvv2.emplace_back("ss", 12);
vvv2.emplace_back("xx", 33);
vvv2.emplace_back("wq", 123);
cout << "------------------------------------------------" << endl;
vector<Girl> vvv3;
vvv3.reserve(10);
vvv3.emplace_back("ss", 12);
vvv3.emplace_back("xx", 33);
vvv3.emplace_back("wq", 123);
cout << "++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
vvv1.erase(vvv1.begin());
cout << "------------------------------------------------" << endl;
vvv1.erase(vvv1.begin());
cout << "++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
vvv2.erase(vvv2.end() - 1);
cout << "------------------------------------------------" << endl;
vvv2.erase(vvv2.end() - 1);
cout << "++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
vvv3.pop_back();
cout << "------------------------------------------------" << endl;
vvv3.pop_back();
cout << "++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
return 1;
}
Girl(string _name, int _age)ss
Girl(string _name, int _age)xx
Girl(string _name, int _age)wq
------------------------------------------------
Girl(string _name, int _age)ss
Girl(string _name, int _age)xx
Girl(string _name, int _age)wq
------------------------------------------------
Girl(string _name, int _age)ss
Girl(string _name, int _age)xx
Girl(string _name, int _age)wq
++++++++++++++++++++++++++++++++++++++++++++++++
operator=(const Girl&)xx
operator=(const Girl&)wq
~Girl()wq
------------------------------------------------
operator=(const Girl&)wq
~Girl()wq
++++++++++++++++++++++++++++++++++++++++++++++++
~Girl()wq
------------------------------------------------
~Girl()xx
++++++++++++++++++++++++++++++++++++++++++++++++
~Girl()wq
------------------------------------------------
~Girl()xx
++++++++++++++++++++++++++++++++++++++++++++++++
~Girl()ss
~Girl()ss
~Girl()wq
从结果中可以看到,如果从中间或开头开始删除,后面的对象由于要向前移动而要调用赋值函数,运行性能偏低。这里移动的方式要注意,它是每二个对象赋值给第一个对象,第三个对象赋值给第二个对象,第三个对象析构销毁。
四、添加新对象时应从结尾处添加,而不要从中间添加
int main() {
vector<Girl> vvv1;
vvv1.reserve(10);
vvv1.emplace_back("ss", 12);
cout << "------------------------------------------------" << endl;
vvv1.insert(vvv1.begin(), Girl("xx", 33));
cout << "------------------------------------------------" << endl;
vvv1.insert(vvv1.begin(), Girl("wq", 123));
cout << "------------------------------------------------" << endl;
cout << "------------------------------------------------" << endl;
vector<Girl> vvv2;
vvv2.reserve(10);
vvv2.emplace_back("ss", 12);
cout << "------------------------------------------------" << endl;
vvv2.emplace(vvv2.begin(), "xx", 33);
cout << "------------------------------------------------" << endl;
vvv2.emplace(vvv2.begin(), "wq", 123);
cout << "------------------------------------------------" << endl;
return 1;
}
Girl(string _name, int _age)ss
------------------------------------------------
Girl(string _name, int _age)xx
Girl(Girl&&)xx
Girl(Girl&&)ss
operator=(const Girl&)xx
~Girl()xx
~Girl()
------------------------------------------------
Girl(string _name, int _age)wq
Girl(Girl&&)wq
Girl(Girl&&)ss
operator=(const Girl&)xx
operator=(const Girl&)wq
~Girl()wq
~Girl()
------------------------------------------------
------------------------------------------------
Girl(string _name, int _age)ss
------------------------------------------------
Girl(string _name, int _age)xx
Girl(Girl&&)ss
operator=(const Girl&)xx
~Girl()xx
------------------------------------------------
Girl(string _name, int _age)wq
Girl(Girl&&)ss
operator=(const Girl&)xx
operator=(const Girl&)wq
~Girl()wq
------------------------------------------------
~Girl()wq
~Girl()xx
~Girl()ss
~Girl()wq
~Girl()xx
~Girl()ss
从运行结果可以看到,无论是使用emplace还是insert,在插入位置后的对象都会发生移动,这样会影响性能。
五、使用std::vector(std::vector)和std::vector(std::initializer_list<T>)对std::vector赋初始值会将std::vector和std::initializer_list<T>中所有对象复制
int main() {
cout << "------------------------------------------------" << endl;
vector<Girl> vv({ Girl("d",90), Girl("ll",80) });
cout << "------------------------------------------------" << endl;
vector<Girl> vvv1;
vvv1.reserve(10);
vvv1.emplace_back("ss", 12);
vvv1.emplace_back("xx", 33);
cout << "------------------------------------------------" << endl;
vector<Girl> vvv2(vvv1);
cout << "------------------------------------------------" << endl;
return 1;
}
------------------------------------------------
Girl(string _name, int _age)d
Girl(string _name, int _age)ll
Girl(const Girl&)d
Girl(const Girl&)ll
~Girl()ll
~Girl()d
------------------------------------------------
Girl(string _name, int _age)ss
Girl(string _name, int _age)xx
------------------------------------------------
Girl(const Girl&)ss
Girl(const Girl&)xx
------------------------------------------------
~Girl()ss
~Girl()xx
~Girl()ss
~Girl()xx
~Girl()d
~Girl()ll
通过运行结果可以看到,当初始化std::vector时,对象双被复制了一份。通过初始化的方式无法将对象在多个集合中共享。如果像让std::vector中的所有对象暴露出来,可以使用T* std::vector.data(),它会返回std::vector中所包含的对象的指针。
六、需要将对象全部转移到另外一std::vector时,应使用std::vector.swap()、std::swap()、std::move(std::vector)
int main() {
{
cout << "------------------------------------------------" << endl;
vector<Girl> vvv1;
vvv1.reserve(10);
vvv1.emplace_back("ss", 12);
vvv1.emplace_back("xx", 33);
vvv1.emplace_back("wq", 123);
cout << "------------------------------------------------" << endl;
vector<Girl> vvv2 = move(vvv1);
cout << "------------------------------------------------" << endl;
}
{
cout << "------------------------------------------------" << endl;
vector<Girl> vvv1;
vvv1.reserve(10);
vvv1.emplace_back("ss", 12);
vvv1.emplace_back("xx", 33);
vvv1.emplace_back("wq", 123);
cout << "------------------------------------------------" << endl;
vector<Girl> vvv2;
vvv2.swap(vvv1);
cout << "------------------------------------------------" << endl;
}
{
cout << "------------------------------------------------" << endl;
vector<Girl> vvv1;
vvv1.reserve(10);
vvv1.emplace_back("ss", 12);
vvv1.emplace_back("xx", 33);
vvv1.emplace_back("wq", 123);
cout << "------------------------------------------------" << endl;
vector<Girl> vvv2;
swap(vvv1, vvv2);
cout << "------------------------------------------------" << endl;
}
return 1;
}
------------------------------------------------
Girl(string _name, int _age)ss
Girl(string _name, int _age)xx
Girl(string _name, int _age)wq
------------------------------------------------
------------------------------------------------
~Girl()ss
~Girl()xx
~Girl()wq
------------------------------------------------
Girl(string _name, int _age)ss
Girl(string _name, int _age)xx
Girl(string _name, int _age)wq
------------------------------------------------
------------------------------------------------
~Girl()ss
~Girl()xx
~Girl()wq
------------------------------------------------
Girl(string _name, int _age)ss
Girl(string _name, int _age)xx
Girl(string _name, int _age)wq
------------------------------------------------
------------------------------------------------
~Girl()ss
~Girl()xx
~Girl()wq
通过运行结果可以看到,转移的过程只是更改了指针的指向,没有发生任何复制或拷贝。
七、如果std::vector中在存放指针对象,即std::vector<T*>,则应使用智能指针
-
std::vector<std::unique_ptr<T>>
-
std::vector<std::shared_ptr<T>>
因为如果std::vector中存放指针,指针指向的对象并不受std::vector管理,所以需要智能指针帮助管理这些对象。