1. 相同点
-
都是往容器(比如
std::vector,std::deque,std::list等)末尾插入一个元素。 -
插入完成后,容器的大小 (
size()) 会增加 1。 -
插入位置都是 容器的尾部,不能指定任意位置。
2. push_back 的语义
vector.push_back(value);
-
作用:把一个 已经构造好的对象 加到容器末尾。
-
参数:只能传入一个已经存在的对象,或者能隐式转换为容器元素类型的对象。
-
过程(以
std::vector<int>为例):-
你先要有一个
int类型的对象; -
push_back会 拷贝构造(或移动构造,如果传右值)一个新的对象到容器末尾。
-
例子:
std::vector<std::string> v;
std::string s = "hello";
// 1. 先构造 s
v.push_back(s); // 拷贝构造
v.push_back(std::move(s)); // 移动构造
v.push_back("world"); // 临时对象 -> 移动/拷贝构造
3. emplace_back 的语义
vector.emplace_back(args...);
-
作用:在容器尾部 就地(in-place)直接构造对象,而不是先构造再拷贝/移动。
-
参数:是容器元素构造函数的参数,会直接传递给元素类型的构造函数。
-
过程(仍以
std::vector<std::string>为例):-
在容器末尾的存储位置上,直接调用构造函数,用传入的参数构造对象;
-
避免了临时对象的产生以及拷贝/移动开销。
-
例子:
std::vector<std::string> v;
// 在 vector 尾部直接用构造函数参数 "hello" 构造一个 string 对象
v.emplace_back("hello"); // 相当于 v.push_back(std::string("hello")),但省掉了临时对象
4. 举例对比
push_back
std::vector<std::pair<int, std::string>> v;
std::pair<int, std::string> p(1, "abc");
// 需要先构造 p,再把 p 拷贝/移动到容器
v.push_back(p); // 拷贝
v.push_back(std::move(p)); // 移动
emplace_back
std::vector<std::pair<int, std::string>> v;
// 直接在容器尾部构造 pair(1, "abc"),避免临时对象
v.emplace_back(1, "abc");
注意:
emplace_back(1, "abc")相当于调用pair<int, string>(1, "abc")构造函数。
而push_back("abc")在这个例子中甚至编译不过,因为参数类型不匹配。
5. 性能差异
-
push_back:-
需要一个已经存在的对象;
-
往容器里放的时候可能涉及 拷贝构造/移动构造。
-
-
emplace_back:-
直接调用构造函数,在容器内存里 原地构造对象;
-
可以省掉一次临时对象的构造与拷贝/移动,效率更高(尤其是对象比较复杂时差距明显)。
-
但要注意:
-
对于 简单类型(如
int,double),性能差距几乎可以忽略。 -
对于 复杂类型(如
std::string,std::map),emplace_back可以避免多余开销。
6. 使用建议
-
如果你 已经有一个对象,用
push_back更自然:
std::vector<Person> v;
Person p("Tom", 20);
v.push_back(p); // 拷贝
v.push_back(std::move(p)); // 移动
- 如果你想 直接构造对象,避免中间的临时变量,用
emplace_back更好:
std::vector<Person> v;
v.emplace_back("Tom", 20); // 直接原地构造 Person("Tom", 20)
7. 容易踩坑的地方
-
坑 1:emplace_back 不等于 push_back
std::vector<std::string> v;
v.push_back("hello"); // OK,隐式转换成 std::string
v.emplace_back("hello"); // OK,直接调用 string(const char*) 构造函数
std::vector<int> vi;
vi.push_back(3.5); // OK,会把 double 转成 int 存进去
vi.emplace_back(3.5); // OK,同样会调用 int 的构造函数,结果也是 int(3.5) -> 3
- 坑 2:emplace_back 可能触发不同的构造函数
struct A {
A(int, double) { std::cout << "A(int,double)\n"; }
A(std::pair<int,double>) { std::cout << "A(pair)\n"; }
};
std::vector<A> v;
v.push_back({1, 2.0}); // 调用 A(pair),因为花括号推断为 pair
v.emplace_back(1, 2.0); // 调用 A(int,double),因为参数直接传给构造函数
8. 总结表格

357

被折叠的 条评论
为什么被折叠?



