here和here中存在类似的问题,但我认为我没有得到明确的答案,然后重新提出问题。
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中实现的,那么我认为它有充分的理由存在。
答案 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}调用的}。
string
和emplace
完全不同的地方是使用不是对象本身的构造函数参数调用push
:emplace
不需要构造临时< em>然后复制到容器中。
emplace
答案 2 :(得分:1)
我需要一段时间才能真正理解使用std :: vector :: emplace作为aschepler所说的优势。
我发现使用的更好方案就是当我们拥有自己的类时,它会在构造时接收一些数据。
为了更清楚,我们假设:
然后我们可以有这样的一行:
vVec.emplace(get1stElem(), get2ndElem(), get3rdElem());
然后std :: vector :: emplace将比std :: vector :: push_back更有效地构建MyObject。