之前往顺序容器中添加元素,基本使用的都是push_back,使用push_back其实是先创建元素,在将元素拷贝到容器中,c11后,push_back可以选择的是创建完元素后,是将元素拷贝or移动到容器内。c11除了这个方面的优化外,还提供了一个添加元素的方法emplace_back:使用该接口将会直接在容器尾部创建元素,不会拷贝or移动。这样对性能是有提升的。看下下面的例子
class emplace_test {
public:
emplace_test(std::string str) : str_(std::move(str)) {
std::cout << "emplace_test construct." << std::endl;
};
emplace_test(const emplace_test& other) : str_(std::move(other.str_)) {
std::cout << "emplace_test copy construct." << std::endl;
}
emplace_test(const emplace_test&& other) : str_(std::move(other.str_)) {
std::cout << "emplace_test move construct." << std::endl;
}
emplace_test& operator=(const emplace_test& other) {
str_ = other.str_;
std::cout << "emplace_test copy =." << std::endl;
return *this;
}
private:
std::string str_;
};
int main() {
std::vector<emplace_test> vec;
vec.reserve(4);
vec.emplace_back(string("222"));
vec.push_back(string("111"));
}
emplace_test construct.
emplace_test construct.
emplace_test move construct.
可以看到emplace_back只有构造函数,而没有拷贝or移动。push_back是除了构造还多了移动
上述示例中,vec.reserve(4);是为了提前申请好内存,否则会可能由于容器容量不够导致重新申请内存,而结果展示就会具有迷惑性如:
//vec.reserve(4);
emplace_test construct.
emplace_test construct.
emplace_test move construct.
emplace_test copy construct.
多了一次拷贝构造,我们可以加日志
class emplace_test {
public:
emplace_test(std::string str) : str_(std::move(str)) {
std::cout << "emplace_test construct." << str_ << std::endl;
};
emplace_test(const emplace_test& other) : str_(std::move(other.str_)) {
std::cout << "emplace_test copy construct." << str_ << std::endl;
}
emplace_test(const emplace_test&& other) : str_(std::move(other.str_)) {
std::cout << "emplace_test move construct." << str_ << std::endl;
}
emplace_test& operator=(const emplace_test& other) {
str_ = other.str_;
std::cout << "emplace_test copy =." << std::endl;
return *this;
}
private:
std::string str_;
};
int main() {
std::vector<emplace_test> vec;
//vec.reserve(4);
std::cout << "vec capacity is "<< vec.capacity() << std::endl;
vec.emplace_back(string("222"));
std::cout << "vec capacity is " << vec.capacity() << std::endl;
vec.push_back(string("111"));
std::cout << "vec capacity is " << vec.capacity() << std::endl;
}
vec capacity is 0
emplace_test construct.222
vec capacity is 1
emplace_test construct.111
emplace_test move construct.111
emplace_test copy construct.222
vec capacity is 2
我们可以看到是因为容量不够,而导致重新申请内存,所以一个优化点是使用vector的时候,我们可以预先指定vector的容量,防止前期添加元素导致频繁的重新申请内存,一个简单测试看看vector的容量增长
std::vector<int> vec;
for (int i = 0; i < 10; i++) {
vec.emplace_back(i);
std::cout << "vec capacity is " << vec.capacity() << std::endl;
}
vec capacity is 1
vec capacity is 2
vec capacity is 3
vec capacity is 4
vec capacity is 6
vec capacity is 6
vec capacity is 9
vec capacity is 9
vec capacity is 9
vec capacity is 13
可以看到在一个简单的十次循环中,vector重新申请内存的次数也是不太能接受的。所以可以根据自己的业务特点,适当的提前规划好vector的容量还是很有必要的