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

The*_*ect 6 c++ string vector c++11

这里这里也存在类似的问题,但我认为我没有得到一个明确的答案然后我重新提出这个问题.

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);
Run Code Online (Sandbox Code Playgroud)

但是当我们谈论对象时,我并不是那么清楚.我们以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); 
Run Code Online (Sandbox Code Playgroud)

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)); 
Run Code Online (Sandbox Code Playgroud)

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));
Run Code Online (Sandbox Code Playgroud)

因为std :: string :: substr返回另一个std :: string,我们和第二个场景有相同的情况?

结论

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

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

asc*_*ler 12

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

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

vVec.push_back(std::string(10, 'x'));
vVec.emplace_back(10, 'x');
Run Code Online (Sandbox Code Playgroud)

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

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


Pas*_* By 9

首先让我们澄清一下:

emplace家庭接受参数的构造函数,而不是对象本身

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

也就是说,将相同类型的对象作为参数正是复制和移动构造正在做的事情,这就是为什么在您的示例中,它们调用相同的构造函数:使用已经构造好的进行调用string

emplacepush完全不同的是,这里emplace被称为与构造函数的参数不是对象本身:emplace不需要构造一个临时的,然后复制到容器中。

std::vector<std::string> strvec;
strvec.emplace_back("abc")  //calls string(const char*)

strvec.push_back("abc")          //is equivalent to...
strvec.push_back(string("abc"))  //which calls string(const char*) then string(string&&)
Run Code Online (Sandbox Code Playgroud)


The*_*ect 2

我花了一段时间才真正理解使用 std::vector::emplace 正如 aschepler 所说的优势。

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

为了更清楚地说明,我们假设我们有:

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

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

vVec.emplace(get1stElem(), get2ndElem(), get3rdElem());
Run Code Online (Sandbox Code Playgroud)

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