从C++11开始,vector提供了emplace_back和emplace_front等emplace*相关的函数,用于替换push*相关函数的功能。emplace*函数的优点在于存储在vector中的对象构造出来后就会直接存放到vector中,不会像push*相关函数那样多出一个拷贝构造的过程。因而emplace*相关的函数的效率高,C++11文档推荐尽量使用emplace*相关的函数。但在使用过程中就发现了问题,举一个例子:
#include <iostream>
#include <sstream>
#include <tuple>
#include <exception>
#include <string>
#include <vector>
using namespace std;
class Girl {
public:
string name;
int age;
Girl() {
cout << "Girl()" << endl;
}
Girl(string _name, int _age) : name(_name), age(_age) {
cout << "Girl(string _name, int _age)" << endl;
}
Girl(const Girl& b) : name(b.name), age(b.age) {
cout << "Girl(const Girl&)" << endl;
}
Girl(Girl&& b) : name(move(b.name)), age(b.age) {
cout << "Girl(Girl&&)" << endl;
}
Girl& operator=(const Girl& b) {
cout << "operator=(const Girl&)" << endl;
this->name = b.name;
this->age = b.age;
return *this;
}
};
int main() {
vector<Girl> bv;
cout << bv.size() << endl;
cout << bv.capacity() << endl;
bv.emplace_back("example1", 1);
cout << bv.size() << endl;
cout << bv.capacity() << endl;
bv.emplace_back("example2", 2);
cout << bv.size() << endl;
cout << bv.capacity() << endl;
bv.emplace_back("example3", 3);
cout << bv.size() << endl;
cout << bv.capacity() << endl;
bv.emplace_back("example4", 4);
cout << bv.size() << endl;
cout << bv.capacity() << endl;
return 1;
}
运行结果:
0
0
Girl(string _name, int _age)
1
1
Girl(string _name, int _age)
Girl(const Girl&)
2
2
Girl(string _name, int _age)
Girl(const Girl&)
Girl(const Girl&)
3
3
Girl(string _name, int _age)
Girl(const Girl&)
Girl(const Girl&)
Girl(const Girl&)
4
4
从结果中可能看到,除第一次外,以后每添加一个新的对象,都会将以前插入的对象拷贝一次,这样岂不是很没有效率?
原来造成这种现象的原因是vector的初始容量不足,造成每次插入新对象时都要扩容,扩容时都会把以前插入的对象通过拷贝构造函数移动到新的存储空间中。要解决这个问题,可以先为vector准备足够的容量,从而避免拷贝的发生。事先设置vector容量可以使用reserve函数,修改后的代码如下:
int main() {
vector<Girl> bv;
bv.reserve(10); /
cout << bv.size() << endl;
cout << bv.capacity() << endl;
bv.emplace_back("example1", 1);
cout << bv.size() << endl;
cout << bv.capacity() << endl;
bv.emplace_back("example2", 2);
cout << bv.size() << endl;
cout << bv.capacity() << endl;
bv.emplace_back("example3", 3);
cout << bv.size() << endl;
cout << bv.capacity() << endl;
bv.emplace_back("example4", 4);
cout << bv.size() << endl;
cout << bv.capacity() << endl;
return 1;
}
运行结果:
0
10
Girl(string _name, int _age)
1
10
Girl(string _name, int _age)
2
10
Girl(string _name, int _age)
3
10
Girl(string _name, int _age)
4
10
从上面结果可以看到,拷贝构造函数没有被调用了,只会调用构造函数,这样vector的效率就会太太提升。
参考文档
C++ vector emplace_back calls copy constructor