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
答案 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{});
相同)。由于您提供了临时属性,因此将调用移动构造函数而不是复制构造函数。