c++ 移动构造函数 - push_back vs emplace_back




11关键字 move (6)

对于push_backemplace_back之间的区别我有点困惑。

void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);

由于有一个push_back超载需要右值引用,我不太明白emplace_back的目的是什么?


Answers

这里显示了一个很好的push_back和emplace_back代码。

http://en.cppreference.com/w/cpp/container/vector/emplace_back

您可以在push_back上看到移动操作,而不是在emplace_back上看到移动操作。


添加到矢量后,符合emplace_back标准的实现将参数传递给vector<Object>::value_type构造函数。 我记得Visual Studio不支持可变模板,但在Visual Studio 2013 RC中将支持可变模板,所以我猜想会添加一个符合签名。

使用emplace_back ,如果将参数直接转发给vector<Object>::value_type构造函数,严格来说,不需要为emplace_back函数移动或复制类型。 在vector<NonCopyableNonMovableObject>情况下,这是没有用的,因为vector<Object>::value_type需要可复制或可移动的类型才能增长。

但是请注意 ,这对于std::map<Key, NonCopyableNonMovableObject>非常有用,因为一旦您在地图中分配了一个条目,它就不再需要被移动或复制了,这与vector不同,意味着您可以使用std::map有效地使用既不可复制也不可移动的映射类型。


除了什么访问者说:

由MSCV10提供的函数void emplace_back(Type&& _Val)是不符合和冗余的,因为正如你所说的那样,它严格地等同于push_back(Type&& _Val)

但真正的C ++ 0x形式的emplace_back真的很有用: void emplace_back(Args&&...) ;

它不采用value_type而是采用可变参数列表,这意味着您现在可以完美地转发参数并直接构建一个对象而不需要临时存储。

这很有用,因为无论有多聪明,RVO和移动语义带来的表格都还有复杂的情况,push_back可能会产生不必要的副本(或移动)。 例如,使用std::map的传统insert()函数,您必须创建一个临时文件,然后将其复制到std::pair<Key, Value> ,然后将其复制到映射中:

std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";

// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString))); 

// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);

那么为什么他们没有在MSVC中实现正确版本的emplace_back呢? 事实上,前段时间它也给我带来了麻烦,所以我在Visual C ++博客上提出了同样的问题。 这里是Microsoft的Visual C ++标准库实现的官方维护者Stephan T Lavavej的回答。

问:现在beta2 emplace函数只是某种占位符吗?

答:你可能知道,可变参数模板在VC10中没有实现。 我们用诸如make_shared<T>() ,元组以及<functional>的新事物之类的预处理器机器来模拟它们。 这种预处理机器使用和维护相对困难。 另外,它会显着影响编译速度,因为我们必须重复包含子标题。 由于我们的时间限制和编译速度问题的结合,我们还没有模拟我们的emplace函数中的可变参数模板。

当可变参数模板在编译器中实现时,您可以期望我们将在库中利用它们,包括在我们的emplace函数中。 我们非常重视合规性,但不幸的是,我们无法立即做所有事情。

这是一个可以理解的决定。 每个试图用预处理器可怕的技巧来模拟可变模板的人都知道这些东西有多恶心。


还有一个列表:

//构建元素。
emplace_back( “元素”);

//它将创建新的对象,然后复制(或移动)其参数值。 的push_back(explicitDataType { “元件”});


下一个例子中可以演示emplace_back优化。

对于emplace_back构造函数将调用A (int x_arg) 。 对于push_back先调用A (int x_arg)再调用move A (A &&rhs)

当然,构造函数必须explicit标记,但是对于当前的示例来说,很好地消除显式性。

#include <iostream>
#include <vector>
class A
{
public:
  A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)\n"; }
  A () { x = 0; std::cout << "A ()\n"; }
  A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)\n"; }
  A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)\n"; }

private:
  int x;
};

int main ()
{
  {
    std::vector<A> a;
    std::cout << "call emplace_back:\n";
    a.emplace_back (0);
  }
  {
    std::vector<A> a;
    std::cout << "call push_back:\n";
    a.push_back (1);
  }
  return 0;
}

输出:

call emplace_back:
A (x_arg)

call push_back:
A (x_arg)
A (A &&)





c++ visual-studio-2010 stl c++11 move-semantics