push_back vs emplace_back 到 std::vector<std::string>

新手上路,请多包涵

此处此处 存在类似的问题,但我认为我们还没有明确的答案,然后我重新提出了问题。

C++11 标准有两种在向量末尾添加新元素的方法,它们是 std::vector::push_backstd::vector::emplace_back

它们之间的区别在于 std::vector::emplace_back 构造对象,而 std::vector::push_back 基本上是复制对象(或原始类型)或将其移动到向量的末尾。

然后 std::vector::push_back 看起来将原始类型添加到 std::vector 中的更好选择。例如:

 std::vector<int> vVec;
vVec.push_back(10);
int iVar 30;
vVec.push_back(iVar);

但是当我们谈论对象时,我并不太清楚。让我们以 std::string 的向量为例。如果我想添加一个文字字符串,我将使用 std::vector::emplace_back 而当我想复制或移动一个字符串对象时,我将使用 std::vector::push_back

为了更清楚我在问什么,让我们看几个场景:

第一种情况:

 std::vector<string> vVec;
std::string sTest("1st scenario");
vVec.push_back(sTest);
vVec.emplace_back(sTest);

Push_back make a copy of sTest and associate to the new element in the end of vVec meanwhile emplace_back create the string object in the end of vVec 并将 sTest 的内容复制到其中。在这种情况下哪个更有效或无关紧要?

第二种情况:

 std::vector<string> vVec;
std::string sTest1("2st scenario");
std::string sTest2("2st scenario");
vVec.push_back(move(sTest1));
vVec.emplace_back(move(sTest2));

Push_back 已准备好移动语义,但是 emplace_back 会发生什么?在这种情况下,哪个更有效?

第三种情况:

 std::vector<string> vVec;
std::string sTest("3st scenario");
vVec.push_back(sTest.substr(4,4));
vVec.emplace_back(sTest.substr(4,4));

因为 std::string::substr 返回另一个 std::string 我们有与第二种情况相同的情况?

结论

如果 std::vector::emplace_backstd::vector::push_back 仅在涉及文字(就地构造)时更有效,那么使用它真的合理吗?如果有,你能给我举一些例子吗?

重要的是要注意 std::vector::emplace_back 是在 c++11 中而不是在 c++0x 中实现的,那么我认为它有充分的理由存在。

原文由 TheArchitect 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

我需要一段时间才能真正理解 aschepler 所说的使用 std::vector::emplace 的优势。

我发现更好的使用场景是当我们有自己的类在构造时接收一些数据。

为了更清楚,让我们假设我们有:

  1. MyObject 的向量
  2. MyObject 需要接收 3 个参数来构造
  3. 函数 get1stElem()、get2ndElem() 和 get3rdElem() 提供了构造 MyObject 实例所需的元素

然后我们可以有这样的一行:

 vVec.emplace(get1stElem(), get2ndElem(), get3rdElem());

然后std::vector::emplace 将比std::vector::push_back 更有效地就地构造MyObject。

原文由 TheArchitect 发布,翻译遵循 CC BY-SA 3.0 许可协议

这在您的三个场景中没有太大区别,因为这两个函数将在场景 1 中调用一个复制构造函数,在场景 2 或 3 中调用一个移动构造函数。

但是如果你想构造一个由 10 个 'x' 字符组成的字符串呢?在这种情况下,您的选择是

vVec.push_back(std::string(10, 'x'));
vVec.emplace_back(10, 'x');

In this case, push_back calling a custom string constructor and then a move constructor, but emplace_back calls the custom string constructor directly,保存对移动构造函数的调用。

std::string 的移动构造函数可能不是什么大问题,但是 emplace 函数可以在对象没有有效的移动构造函数时保存,即使类类型有出于某种原因删除了移动构造函数。 (好吧, std::vector 如果你删除移动和复制构造函数,你会不高兴,但其他容器可以接受。)

原文由 aschepler 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题