之前看1002. 查找常用字符题解的时候,发现有人用了emplace_back,将char转型成了string塞进了
vector<string>
,感觉是个骚操作。
之前也看过emplace_back和push_back的区别, 只不过又忘记了, 因此本次也算个防忘系列把…
1 | vector<string> ans; |
在STL中,进行插入元素的时候,有insert和push两种选择方式,而在有了右值引用和移动语义的时候,在C++11中就提出了更高效的插入方法:emplace_back
目前的趋势是希望:使用emplace_back()取代push_back()
据统计,emplace_back()函数要比push_back()函数要快一倍。
empalce与push的区别:
- push_back()函数向容器中加入一个临时对象(右值元素)时, 首先会调用构造函数生成这个对象,然后调用拷贝构造函数将这个对象的拷贝放入容器中, 最后释放临时对象,这样造成的问题是临时变量申请的资源就浪费。但是emplace_back()函数向容器中中加入临时对象, 临时对象原地构造,只有转移的过程,没有赋值或拷贝的操作(不需要触发拷贝构造)。
emplace_back中调用构造函数
1 |
|
▲看到noted标出来的地方后, 就能知道Leetcode题解中的骚操作其实就是根据T类型判断出了调用构造函数。按如下代码得证
1 | string a(1, 'a'+ 1); |
引申:什么是std::move?
借鉴:
在C++11中,标准库在
<utility>
中提供了一个有用的函数std::move,std::move并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue);
- 左值的声明符号为”&”, 为了和左值区分,右值的声明符号为”&&”。
- 临时对象是作为右值处理的
右值引用的意义
直观意义:为临时变量续命,也就是为右值续命,因为右值在表达式结束后就消亡了,如果想继续使用右值,那就会动用昂贵的拷贝构造函数。(关于这部分,推荐一本书《深入理解C11》)
右值引用是用来支持转移语义的。转移语义可以将资源 ( 堆,系统对象等 ) 从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁,能够大幅度提高 C 应用程序的性能。临时对象的维护 ( 创建和销毁 ) 对性能有严重影响。
转移语义是和拷贝语义相对的,可以类比文件的剪切与拷贝,当我们将文件从一个目录拷贝到另一个目录时,速度比剪切慢很多。
通过转移语义,临时对象中的资源能够转移其它的对象里。
在现有的 C++ 机制中,我们可以定义拷贝构造函数和赋值函数。要实现转移语义,需要定义转移构造函数,还可以定义转移赋值操作符。对于右值的拷贝和赋值会调用转移构造函数和转移赋值操作符。如果转移构造函数和转移拷贝操作符没有定义,那么就遵循现有的机制,拷贝构造函数和赋值操作符会被调用。
普通的函数和操作符也可以利用右值引用操作符实现转移语义。
extra:
- std::move执行一个无条件的转化到右值。它本身并不移动任何东西;
- std::forward把其参数转换为右值,仅仅在那个参数被绑定到一个右值时;
- std::move和std::forward在运行时(runtime)都不做任何事。
Author: Mrli
Link: https://nymrli.top/2020/10/18/emplace-back与push-back/
Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.