emplace_back一定比push_back好吗
公司可信考试中经常提到用emplace_back替换push_back来提升性能,因此经常有人一股脑将所有push_back替换为emplace_back,那么emplace_back一定比push_back好吗?
首先来看一个emplace_back的简易实现:
template<typename T, typename... Args>
T& emplace_back(Args&&... args)
{
m_currentIndex++;
T* p = new(m_data + m_currentIndex) T(std::forward<Args>(args)...);
return *p;
}
emplace_back内部实现是在容器的指定位置直接使用参数作为构造函数的参数构造一个新对象,并将对象的引用返回出来。
对于需要构造一个新对象放入容器的场景,相比push_back可以少一次拷贝。例如:
// 实现1
Point pos(100, 200);
pos.x += move.x;
container.push_back(pos);
// 实现2
Point &pos = container.emplace_back(100, 200);
pos.x += move.x;
可以看到实现2直接在容器内指定位置创建对象,然后再修改对象熟悉。实现1先构造了对象完成属性修改,push_back时仍需要将栈上的对象拷贝到容器的指定位置。实现1比实现2多了一次拷贝操作。
但如果将实现1的push_back直接替换成emplace_back:
Point pos(100, 200);
pos.x += move.x;
container.emplace_back(pos);
先构造了对象完成属性修改,再在容器的指定位置使用拷贝构造又构造了一遍。这样使用并没有减少拷贝,同时忽略了emplace_back返回值。
另外所有场景的push_back都可以替换成emplace_back吗?当对象本身已经构造好了,只是需要拷贝到容器内时,emplace_back并没有什么价值,例如:
// 实现1
void onMousePressed(const Point& pos) {
container.push_back(pos);
}
// 实现2
void onMousePressed(const Point& pos) {
container.emplace_back(pos);
}
此时不管用谁都是将对象拷贝到容器的指定位置,但emplace_back多余地将新建的对象引用返回了。
评论区