欢迎关注本公众号,专注面试题拆解
分享一套视频课程《C++百万并发服务器开发》,有需要的加我微信获取:fb964919126
面试题:C++ vector 中的 push_back() 和 emplace_back() 的区别、以及使用场景。
这也是一道高频面试题,基本校招必问题,需要掌握。
push_back() 的工作原理
emplace_back() 的工作原理
特性 | push_back() | emplace_back() |
基本功能 | 将一个已构造的对象复制或移动到容器 | 在容器中完成直接构造对象 |
是否需要构造临时对象 | 是,需要先构造对象再插入 | 否,直接在容器内构造对象 |
构造与性能 | 可能涉及一次复制或移动(依赖于对象类型和语义) | 无需拷贝或移动,直接调用构造函数 |
参数传递 | 需要完整的对象作为参数 | 直接传递构造对象的参数 |
push_back()
收到一个对象的副本,或者右值引用。
如果格式化是一个临时对象(右值),且类支持移动语义,则调用其移动构造函数。
如果确定左值,则需要调用拷贝构造函数。
class A {
public:
A(int x) : x(x) { std::cout << "Constructed A\n"; }
A(const A& other) { std::cout << "Copy Constructed A\n"; }
A(A&& other) noexcept { std::cout << "Move Constructed A\n"; }
int x;
};
int main() {
std::vector<A> vec;
A a(10); // Constructed A
vec.push_back(a); // Copy Constructed A
vec.push_back(A(20));// Constructed A, Move Constructed A
return 0;
}
实际运行发现会多输出一次Move,原因是因为vector发生了扩容.
emplace_back()
不需要构造一个临时对象,而是直接在容器内调用构造函数构造对象。
可以减少临时对象的创建、拷贝或移动,从而提升性能。
#include <vector>
#include <iostream>
class A {
public:
A(int x) : x(x) { std::cout << "Constructed A\n"; }
A(const A& other) { std::cout << "Copy Constructed A\n"; }
A(A&& other) noexcept { std::cout << "Move Constructed A\n"; }
int x;
};
int main() {
std::vector<A> vec;
vec.emplace_back(10); // Constructed A (直接在容器中构造,无拷贝或移动)
return 0;
}
性能对比
push_back():
首先构造一个临时对象
将这个临时对象拷贝或移动到 vector 的存储空间
销毁临时对象
这个过程中涉及多次构造和销毁操作
emplace_back():
直接在vector 的存储空间构造对象,
避免了临时对象的创建和销毁,减少了内存操作。
emplace_back()通常比较push_back()高效,尤其是在以下情况下:
对象的构造和复制成本更高(例如复杂的自定义类型)。
构造临时对象需要额外的计算时间。
使用场景
适合使用 push_back() 的情况
1、当对象已经存在
std::string str = "Hello";
std::vector<std::string> vec;
vec.push_back(str); // 这里使用 push_back 更直观
在这种情况下,对象已经构造完成,使用 push_back() 更符合直觉。
2、需要多次使用同一个对象时
MyClass obj(1, 2);
vec1.push_back(obj);
vec2.push_back(obj);
map1[key] = obj;
当需要在多个地方使用同一个对象时,我个人认为先构造对象再使用 push_back() 是更好的选择。
适合使用 emplace_back() 的情况
1、避免临时对象
std::vector<A> vec;
vec.emplace_back(10); // 直接构造,无需临时对象
2、复杂构造函数
std::vector<std::pair<int, std::string>> vec;
vec.emplace_back(1, "example"); // 直接构造 std::pair<int, std::string>
3、对象构造参数较多时
struct Complex {
Complex(int a, int b, int c, std::string d) {}
};
std::vector<Complex> vec;
// emplace_back 可以直接传递构造参数
vec.emplace_back(1, 2, 3, "test");
// push_back 需要显式构造对象
vec.push_back(Complex(1, 2, 3, "test"));
性能考虑
对于简单类型(如 int),两者性能差异很小
对于复杂对象,emplace_back() 通常能提供更好的性能
具体性能差异需要通过实际测试来确定。
使用建议
默认优先使用 push_back(),代码更清晰直观
在性能关键的场景,考虑使用 emplace_back()
对于复杂对象的直接构造,优先使用 emplace_back()
end
CppPlayer
关注,回复【电子书】珍藏CPP电子书资料赠送
精彩文章合集
专题推荐