欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

push_back与emplace_back之间的区别

程序员文章站 2022-03-22 20:59:29
...


1.左值与右值

  • 左值:占用了一定内存,且拥有可辨认的地址的对象
  • 右值:左值以外的所有对象

值得一提的是,左值的英文简写为“lvalue”,右值的英文简写为“rvalue”。很多人认为它们分别是"left value"、“right value” 的缩写,其实不然。

  • lvalue 是“loactor value”的缩写,可意为存储在内存中、有明确存储地址(可寻址)的数据。
  • rvalue 是 "read value"的缩写,指的是那些可以提供数据值的数据(不一定可以寻址,例如存储于寄存器中的数据)。
  • 通常情况下,判断某个表达式是左值还是右值,最常用的有以下 2 种方法。
  • [1] 可位于赋值号(=)左侧的表达式就是左值;反之,只能位于赋值号右侧的表达式就是右值
int a = 5;
5 = a; 			//错误,5 不能为左值
  • 其中,变量 a 就是一个左值,而字面量 5 就是一个右值。值得一提的是,C++ 中的左值也可以当做右值使用,例如:
int b = 10; 	// b 是一个左值
a = b; 			// a、b 都是左值,只不过将 b 可以当做右值使用
  • [2] 有名称的、可以获取到存储地址的表达式即为左值;反之则是右值。
  • 以上面定义的变量 a、b 为例,a 和 b 是变量名,且通过 &a 和 &b 可以获得他们的存储地址,因此 a 和 b 都是左值;
  • 反之,字面量 5、10,它们既没有名称,也无法获取其存储地址(字面量通常存储在寄存器中,或者和代码存储在一起),因此 5、10 都是右值。

2.emplace_back()

  • c++11新加入了emplace_back():
  • push_back():通常使用push_back()向容器中加入一个右值元素(临时对象)时,首先会调用构造函数构造这个临时对象,然后需要调用拷贝构造函数将这个临时对象放入容器中。原来的临时变量释放。这样造成的问题就是临时变量申请资源的浪费。
  • emplace_back()引入了右值引用,直接在容器的末尾构造对象,这样就省去了拷贝构造的过程。
template <class... Args>
  void emplace_back (Args&&... args);
  • 例子:
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
    
class A {
public:
    A(int i){
        str = to_string(i);
        cout << "  构造函数" << endl; 
    }
    
    A(const A& other): str(other.str){
        cout << "××拷贝构造" << endl;
    }
    
    ~A(){}
    
public:
    string str;
};
    
int main()
{
    vector<A> vec;
    vec.reserve(10);

    cout << "--------- push_back ---------\n";
    // 调用了3次构造函数,和3次拷贝构造函数,
    for(int i=0; i<3; i++){
        vec.push_back(A(i));
    }

    cout << "--------- emplace_back ---------\n";
    // 调用了3次构造函数, 0次拷贝构造函数
    for(int i=0; i<3; i++){
        vec.emplace_back(i); 
    }

}
  • 输出结果:
--------- push_back ---------
  构造函数
××拷贝构造
  构造函数
××拷贝构造
  构造函数
××拷贝构造
--------- emplace_back ---------
  构造函数
  构造函数
  构造函数

相关标签: C++ c++