为什么vector.emplace_back会调用move-constructor?

时间:2014-02-18 15:29:16

标签: c++ vector

struct Object {  
    Object() { cout << "constructor\n"; }
    Object(const Object &) { cout << "copy constructor\n"; }
    Object(Object &&) { cout << "move constructor\n"; }
};

int main() {
    vector<Object> v;
    v.reserve(10);
    v.emplace_back(Object{});
}

这给了我以下输出:

  

构造
  移动构造函数

为什么呢?我认为emplace_back确实创建了Object,因此不必调用复制或移动构造函数 从描述:

  

元素是就地构造的,即不执行复制或移动操作。

编辑:啊,好吧,似乎我从根本上误解了emplace_back()。您不必将Object作为参数,因为它会自动为您创建。您只需将Object-constructor的参数提供给emplace_back()。

所以,如果我有一个像这样的新构造函数:

Object(int) { cout << "int constructor\n"; }   

我会像这样打电话给emplace_back:

v.emplace_back(42);  

而不是:

v.emplace_back(Object(42));

现在有道理,非常感谢!

EDIT2:我希望我能接受你所有的答案! :-P

5 个答案:

答案 0 :(得分:17)

emplace_back将其参数转发给vector元素类的构造函数,在vector的下一个可用位置就地调用。

v.emplace_back(Object{});

等同于:

{
     Object tmp;
     v.emplace_back(std::move(tmp));
}

这就是为什么你得到一个常规的构造函数调用,然后是一个移动构造函数调用。 如果要使用emplace_back附加新对象,只需调用:

v.emplace_back();

为了完整起见,emplace_back可能会调用移动构造函数的另一个原因是:emplace_back可能导致vector增长,从而将其初始内容移动到新的记忆位置。这不是问题所在,因为调用reserve可以保证足够的容量,但通常它是问题的答案。

答案 1 :(得分:9)

v.emplace_back(Object{});会调用展示位置new (place) Object(Object{})作为移动构造函数。

使用v.emplace_back();来避免调用额外的对象构造函数,
这将导致new (place) Object;

答案 2 :(得分:6)

emplace_back调用任何构造函数匹配您传递它的参数。在这种情况下,您已选择传递与Object{}移动构造函数匹配的Object&&

当描述说“不执行移动或复制”时,它意味着除了您指定的对象构造。如果这种结构恰好是移动或复制,那么它当然会被执行。

如果您希望emplace_back使用no-args构造函数,则不传递任何参数:v.emplace_back()

答案 3 :(得分:3)

您链接的版本用于传递构造函数参数。要达到预期效果,您可以拨打v.emplace_back();

答案 4 :(得分:1)

您正在使用存储在向量中的相同类型的对象调用emplace_back,因此您要请求该对象的副本(与Object O(Object{});相同)。由于您提供了临时属性,因此将调用移动构造函数而不是复制构造函数。