C/C++---emplace和emplace_back
在C++中,emplace和emplace_back是容器(如vector、list、map等)提供的用于插入元素的成员函数。它们是C++11引入的特性,主要优势在于能够直接在容器的内存位置上构造对象,而不需要先创建临时对象再将其复制或移动到容器中。
1. emplace_back
适用容器:vector、deque、list 等支持尾部插入的容器。
功能:在容器尾部直接构造一个新元素,参数是元素类型的构造函数参数。
示例:
#include <vector>
#include <string>
#include <iostream>struct Person {std::string name;int age;// 构造函数Person(const std::string& n, int a) : name(n), age(a) {}
};int main() {std::vector<Person> people;// 传统方式:先创建临时对象,再移动到容器people.push_back(Person("Alice", 25));// emplace_back 方式:直接在容器内存中构造对象people.emplace_back("Bob", 30); // 直接传递构造函数参数for (const auto& p : people) {std::cout << p.name << ", " << p.age << std::endl;}return 0;
}
输出:
Alice, 25
Bob, 30
优势:
- 效率更高:避免了临时对象的创建和移动操作。
- 语法更简洁:直接传递构造参数,无需显式创建对象。
2. emplace
适用容器:关联容器(如map、set)、无序容器(如unordered_map、unordered_set)、适配器容器(stack、queue、priority_queue)。
功能:在容器的适当位置直接构造一个新元素,参数是元素类型的构造函数参数。
示例(map):
std::stack<int> stk;
stk.emplace(42); // 正确
// stk.emplace_back(42); // 错误:stack没有emplace_back
#include <map>
#include <string>
#include <iostream>int main() {std::map<int, std::string> myMap;// 传统方式:先创建临时 pair,再插入myMap.insert(std::make_pair(1, "apple"));// emplace 方式:直接构造 pairmyMap.emplace(2, "banana"); // 直接传递 pair 的构造参数for (const auto& pair : myMap) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;
}
输出:
1: apple
2: banana
优势:
- 避免临时对象:对于
map和unordered_map,无需显式构造std::pair。 - 自动处理重复键:若键已存在,元素不会插入(与
insert行为一致)。
3. 区别与注意事项
| 特性 | emplace_back | emplace |
|---|---|---|
| 适用容器 | 序列容器(如vector、list) | 关联容器(如map、set) |
| 插入位置 | 容器尾部 | 自动排序的合适位置(关联容器) |
| 参数 | 元素类型的构造参数 | 元素类型的构造参数 |
| 返回值 | void | pair<iterator, bool>(是否插入成功) |
| 场景 | 推荐方法 | 示例代码 |
|---|---|---|
| stack/queue 压栈 | emplace | stk.emplace(42); |
| vector 尾部插入 | emplace_back | vec.emplace_back(42); |
| vector 任意位置插入 | emplace(iterator) | vec.emplace(vec.begin(), 42); |
注意事项:
- 参数匹配:传递的参数必须能被元素类型的构造函数接受。
- 移动语义:若元素类型支持移动构造,
push_back/insert可能也很高效,但emplace仍可能更优。 - 异常安全:若构造函数抛出异常,容器状态保持不变。
总结
- 优先使用
emplace_back/emplace:在性能敏感场景或构造参数复杂时。 - 兼容性:若需要兼容旧代码或明确依赖临时对象的创建(如触发特定构造函数),仍可使用
push_back/insert。
