push_back VS emplace_back


C++

C++ 容器 vector, list, deque 都提供了针对序列容器尾部的操作,比如 push_back,pop_back。C++11 提供了新的操作: emplace_back。两者有何区别呢

c.push_back(x)
c.pop_back()
c.emplace_back(args)

push_back 的输入参数为要插入的容器元素对象,容器通过拷贝或者移动该对象把它放入容器的末尾。emplace_back 则不同,它的接受参数为构造容器元素所需要的参数,容器会使用这些参数直接在容器内的对应位置创建容器对象。

举个🌰:

class Student {
    Student(string name, int age, string address);

private:
    std::string address;
    std::string name;
    int age;
}

如果是使用 push_back,需要先构造 Student 对象然后把该对象通过 push_back 拷贝到容器中

void use(vector<Student>& students) {
    Student s ("Carina", 7, "GUANHEJINTING");
    students.push_back(s);
}

如果是使用 emplace_back,直接把构造 Student 需要的参数传递给 emplace_back 即可

void use(vector<Student>& students) {
    students.emplace_back("Carina", 7, "GUANHEJINTING");
}    

由此我们可以看到使用 push_back 会多了一步对对象拷贝或者移动的工作。如果对于一些对象这个操作(拷贝或者移动)比较耗时的情况,优先使用 emplace_back 会比较好一点。对于大部分情况来说,这个效率问题都应该不是问题。

emplace_back 有另外的一个缺点,由于它要根据参数构造一个容器元素,它构造元素的路径可能不是我们的原意,比如可能经过了不易觉察的隐式转换。比如下面的代码,容器会使用 20 来构造一个 std::vector,这样在 vs 中就插入了一个包含 20 个元素的 vector,而不是插入了 20 本身。这种错误只有在运行时才能得到体现。

std::vector<std::vector<int>> vs;
vs.emplace_back(20);

此外,insert 和 emplace (相比于 push_back, emplace_back), 也有类似的区别

参考