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

时间:2017-04-24 19:40:24

标签: c++ string c++11 vector

herehere中存在类似的问题,但我认为我没有得到明确的答案,然后重新提出问题。

C ++ 11标准有两种方法可以在向量的末尾添加一个新元素,它们是std :: vector :: push_back和std :: 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制作sTest的副本并关联到vVec末尾的新元素,同时emplace_back在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_back仅在涉及文字时(就地构造)比std :: vector :: push_back更有效,它是否真的合理使用?如果有的话,你能给我一些例子吗?

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

3 个答案:

答案 0 :(得分:8)

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

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

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

在这种情况下,push_back涉及调用自定义string构造函数,然后调用移动构造函数,但emplace_back直接调用自定义string构造函数,将调用保存到移动构造函数。

std::string的移动构造函数可能不是很大,但emplace函数可以在对象没有高效的移动构造函数时保存,并且即使类类型具有由于某种原因删除了移动构造函数。 (好的,如果删除移动和复制构造函数,std::vector将不会高兴,但其他容器也可以使用它。)

答案 1 :(得分:6)

首先让我们澄清:

emplace系列接受 参数 作为构造函数,而不是对象本身

然后用这些参数构造对象到位,它永远不会构造临时对象,然后将其复制或移动到容器中。

也就是说,取一个与参数相同类型的对象正是复制和移动构造正在做的事情,这就是为什么在你的例子中,它们调用相同的构造函数:它们是用已构造的{{1}调用的}。

stringemplace完全不同的地方是使用不是对象本身的构造函数参数调用pushemplace不需要构造临时< em>然后复制到容器中。

emplace

答案 2 :(得分:1)

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

我发现使用的更好方案就是当我们拥有自己的类时,它会在构造时接收一些数据。

为了更清楚,我们假设:

  1. MyObject的矢量
  2. MyObject需要接收3个要构造的参数
  3. 函数get1stElem(),get2ndElem()和get3rdElem()提供构造MyObject实例所需的元素
  4. 然后我们可以有这样的一行:

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

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