emplace 是 C++ 中标准库(STL)提供的一种高效的元素插入方式,常用于容器(如 std::vector, std::map, std::unordered_map 等)中。emplace 通过直接在容器内部构造元素,避免了不必要的拷贝或移动操作,从而提高了性能。

emplaceinsert 的区别

  • **insert**:将一个已构造的对象插入到容器中。通常需要通过拷贝或移动构造将元素插入容器。

    1
    2
    3
    std::vector<int> vec;
    int x = 5;
    vec.insert(vec.end(), x); // 插入时会发生一次拷贝构造
  • **emplace**:直接在容器内部构造元素,避免了额外的拷贝或移动操作。emplace 接受构造元素所需的参数,然后直接在容器中构造该元素。

    1
    2
    std::vector<int> vec;
    vec.emplace_back(5); // 在容器内部构造元素,避免拷贝

为什么使用 emplace

  1. 避免不必要的拷贝或移动

    • insert 必须先构造一个对象,然后将该对象插入容器,这可能涉及拷贝或移动构造。
    • emplace 直接在容器中构造元素,省去了额外的拷贝或移动操作。
  2. 提高效率

    • 特别是在容器中插入复杂对象时,使用 emplace 能显著提高性能,因为它直接传递构造参数,而不需要先创建一个对象。

常见的 emplace 使用场景

  • **emplace_back**:用于 std::vector 等容器,在容器的末尾构造元素。

    1
    2
    std::vector<std::pair<int, std::string>> vec;
    vec.emplace_back(1, "apple"); // 直接构造元素
  • **emplace**:对于 std::mapstd::unordered_map 等关联容器,在指定位置构造元素。

    1
    2
    std::map<int, std::string> m;
    m.emplace(1, "apple"); // 直接在 map 中构造一个键值对
  • **emplace_front**:用于 std::list 等容器,在容器的前面构造元素。

    1
    2
    std::list<int> lst;
    lst.emplace_front(10); // 在容器前面直接构造一个元素

emplace 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <vector>
#include <map>

int main() {
// 使用 emplace_back 在 vector 中插入元素
std::vector<int> vec;
vec.emplace_back(10); // 直接构造元素
vec.emplace_back(20);

for (const auto& val : vec) {
std::cout << val << " "; // 输出: 10 20
}

std::cout << std::endl;

// 使用 emplace 在 map 中插入元素
std::map<int, std::string> m;
m.emplace(1, "apple");
m.emplace(2, "banana");

for (const auto& pair : m) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

// 输出:
// 1: apple
// 2: banana

return 0;
}

总结

  • emplace 提供了比 insert 更高效的方式来插入元素,因为它避免了不必要的对象构造、拷贝或移动操作。
  • emplace 通过传递构造元素所需的参数,直接在容器内构造元素,而不是先创建元素再插入。
  • 常见的 emplace 变种有 emplace_back(用于 std::vector)、emplace(用于 std::map, std::unordered_map 等)以及 emplace_front(用于 std::list)。

使用 emplace 可以让你的程序更加高效,尤其是在需要频繁插入复杂对象时。