今天在写项目的时候遇到一个常见需求:
- 创建一个用户对象
- 设置一些它的属性
- 放入vector中
实现很容易,但是我想着能不能提高一下效率。因为以前学习八股文的时候了解一些:移动构造函数、emplace_back 、move 等方法可以提高效率,那实际应该如何用呢?
总结一下问题:
- ?是否可以使用移动构造提高效率?
- ?有无移动构造函数与用emplace_back 和push_back有关系吗?
- ?使用emplce_back 替换 push_back 是否可以提高效率?
经过一番折腾,挨个回答一下:
-
?是否可以使用移动构造?
本项目中是不行的。
移动构造加速的本质是不需要重新 new 空间了。 一开始只有深拷贝和浅拷贝。但是这两要么危险,要么new 耗时间。移动构造直接不用new了,直接把指针重新指向不就好。所以估计只能是在有大量堆对象的时候可以提升速度,代替默认的浅拷贝。我们这里的类没有指针成员,所以不行。 -
?有无移动构造函数与用emplace_back 和push_back有关系吗?
本项目中是不行的。
- Emplace_back 没关系。是无需任何移动和拷贝的,和移动构造没关系。
- Push_back 有关系。它优先选择移动构造函数,如果没有才调用拷贝构造。
这里需要知道上面两个的本质:
- push_back:首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中
- emplace_back :则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。 -
使用 emplce_back 替换 push_back 是否可以提高效率?
可以,但是不能够直接替换。好像是因为如果你先创建对象,然后再插入。这种方式用两个都是一样的。
但是我们可以把上面的流程改一下:先在容器尾部创建对象,然后修改最后的元素就好。
第一步先定义一个类A
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <random>
#include <numeric>
using namespace std;
class A
{
public:
int num;
A(int num_)
{
num = num_;
std::cout << "Default Constructor" << std::endl;
}
A(const A & data)
{
num = data.num;
std::cout << "Copy Constructor" << std::endl;
}
~A()
{
std::cout << "Destructor" << std::endl;
}
};
两种方法的对比:
int main()
{
// 测试一下创建10个对象的时间
vector<A> vec;
vec.reserve(30);
// 方式1:老旧的方法:0.015s
/*
clock_t start_time = clock();
for (int i = 0; i < 10; i++)
{
cout << "开始 " << endl;
A tempA(i);
vec.push_back(tempA);
cout << " " << endl;
}
clock_t end_time = clock();
cout << "The run time is: " << (double)(end_time - start_time) / CLOCKS_PER_SEC << "s" << endl;
*/
// 方式2:新的方法:0.003s
clock_t start_time = clock();
for (int i = 0; i < 10; i++)
{
cout << "开始 " << endl;
vec.emplace_back(i);
A & tempA = vec.back();
tempA.num = tempA.num * tempA.num;
cout << " " << endl;
}
clock_t end_time = clock();
cout << "The run time is: " << (double)(end_time - start_time) / CLOCKS_PER_SEC << "s" << endl;
}