c++push_back 以及 emplace_back 的区别
区别
都说emplace快push慢,今天就详细研究下到底两者有什么区别,以及这个move在中间扮演了一个什么角色。
先上测试代码,是一个自己手写的str字符串类,几种构造函数,都写全了:
class str {
public:
friend ostream& operator <<(ostream& out, const str& p);
str() :data(nullptr), len(0) {}
//构造函数
str(const char* p) {
len = strlen(p);
data = new char[len + 1];
strcpy(data, p);
cout << "执行了char * 的构造函数" << endl;
}
//拷贝构造函数
str(const str& p) {
len = p.len;
data = new char[len+1];
strcpy(data, p.data);
cout << "执行了 拷贝构造函数" << endl;
}
//重载赋值函数
str& operator = (const str & p){
if (this == &p) return *this;
delete []data;
len = p.len;
data = new char[len + 1];
strcpy(data, p.data);
cout << "执行了拷贝赋值" << endl;
return *this;
}
//移动构造函数
str(str&& p) {
if (this != &p) {
len = p.len;
data = p.data;
p.data = nullptr;
p.len = 0;
cout << "执行了移动构造" << endl;
}
}
~str() {
delete[]data;
cout << "执行了析构" << endl;
}
private:
char * data;
int len;
};
ostream& operator<<(ostream& out, const str& p) {
out << p.data;
return out;
}
下面开始分析:
先看看pushback做了什么
vector<str> test;
test.push_back("qqqqq");
结果显示:
执行了一次char *的构造函数又
执行了一次移动构造函数!
那么pushback的过程就很清楚了,在推入的是一组数据的时候,pushback会先调用构造函数,生成一个临时的变量(如果你有看我上一篇文章你就知道,这是一个右值!)生成完毕后,会在vector内部的连续存储区域开辟一块空间,然后把这个临时对象拷贝过去!
由于这是一个右值,我的str恰巧又写了移动构造函数,所以理所当然的调用了移动构造函数,效率还是快的,加入我没有写移动构造函数呢?那么就会调用拷贝构造函数。简而言之,pushback对于一组数据的输入就是两个过程,一次构造,一个拷贝构造(移动构造)!效率还是差的!
str s1("ppppp");
cout << "执行push_back" << endl;
vector<str> test;
test.push_back(s1);
这次显示只调用了一次拷贝构造,完成了一次拷贝而已,因为已经存在现成的对象了。
那咱们再来看看emplace_back:
vector<str> test;
test.emplace_back("1111111");
结果显示:只进行了一次构造函数。
那过程也很明白了,把数据拿过去,在原地构造了一边,对比push_back来说可就省了一次拷贝哦!
vector<str> test;
test.emplace_back(s1);
再来看看这种情况呢
结果显示:执行了一次拷贝构造!看来和push_back一样,本身这就是最优化的选择了!
本着刨根问底,这次向c++祖坟刨,再来看看move:
str s1("ppppp");
vector<str> test;
test.emplace_back(move(s1));
test.push_back(move(s1));
test.push_back(move("ppppp"));
结果显示 前两个为移动构造
最后一个仍旧是 构造+拷贝构造
结果显而易见了,move和这两个其实是没什么关系的哦!很多人都被emplace接受的变量为右值引用给弄混了!
结论
1:move之决定了是调用拷贝构造,还是调用移动构造!
2:emplace使用原地构造的方式,但是如果给的是一
现成的对象,就会执行拷贝构造!效果和push一样!如果给的是原始数据,就执行原地构造效果就好了!
3:push_back如果给了原始数据,那么就执行构造+拷贝构造(有移动构造优先移动)如果给的是现成对象,那是纯拷贝构造了,和emplace没啥区别。
4:显而易见,emplace更加优越!尤其是在给定原始数据的时候!并且,当一个类不允许使用拷贝构造的时候,那么push一个原始的结果就是错的!只能用emplace原地构造这个数据!
ps:在实现一个线程池的时候,就有这样的错误!
推荐阅读
-
ajax请求post和get的区别以及get post的选择
-
pyhton链式赋值在可变类型/不可变类型上的区别以及其本质
-
Python import用法以及与from...import的区别
-
解析PHP跳出循环的方法以及continue、break、exit的区别介绍
-
详谈Pandas中iloc和loc以及ix的区别
-
wordpress网站外链nofollow以及域名是否www的区别
-
进制转换以及byted与str的区别
-
浅析php中抽象类和接口的概念以及区别
-
MySQL存储引擎以及MyISAM与InnoDB的区别详解
-
如何解决Ajax访问不断变化的session的值不一致以及HTTP协议中的GET、POST的区别