在Effective Modern C++的第 41 条中, Scott Meyers 提到了这种差异及其对插入效率的影响。
我对此有一些疑问,但在提出问题之前,我需要了解这两种添加元素的方式之间的区别是什么。
考虑书中的代码示例:
std::vector<std::string> vs;
// adding some elements to vs
vs.emplace(v.begin(), "xyzzy");
很明显,之后// adding some elements to vs
,可能是
vs.capacity() == vs.size()
, 或者vs.capacity() > vs.size()
.
相应地,
vs
必须重新分配,并且(在重新分配发生之前vs
名为vs[0]
, , ... 的那些元素)中的所有预先存在的元素都必须移动构造到新的内存位置( , , ...的新位置)vs[1]
vs[1]
vs[2]
vs
必须vs.resize(vs.size() + 1)
并且所有预先存在的元素都必须移动分配给下一个索引,显然是向后处理,从最后一个元素到第一个元素。
(显然我提到了移动操作,因为std::string
提供了noexcept
移动操作。如果不是这种情况,那么上面的场景略有不同,将使用复制操作。)
然而,我的问题的症结所在,就在上面的代码之后,书上写着(我的斜体)
[…]很少有实现会将添加
std::string
到vs[0]
. 相反,他们会将值移动分配到位。[…]
在完成房间以容纳新元素之后,这两种情况是什么?
- 如果
emplace
通过移动赋值添加元素,这意味着它在v[0] = std::string{strarg};
wherestrarg == "xyzzy"
,对吗? - 但是构造被 占据的元素的另一种情况是
v[0]
什么?是安置new
吗?它会是什么样子?我想它应该类似于Placement new here部分的代码块,但我不确定在这种情况下它会是什么样子。