【发布时间】:2014-01-03 09:30:16
【问题描述】:
我正在使用 MSVC,Visual Studio 2013。
假设我有一个结构:
struct my_pair {
int foo, bar;
};
我想有效地添加一堆这些,而不是创建一个临时然后丢弃它:
vector<my_pair> v;
v.push_back(41, 42); // does not work [a]
v.push_back({41,42}); // works [b]
v.emplace_back(41,42); // does not work [c]
v.emplace_back({41,42}); // does not work [d]
v.emplace_back(my_pair{41,42}); //works [e]
现在,如果我在代码中添加构造函数和复制构造函数:
my_pair(int foo_, int bar_) : foo(foo_), bar(bar_)
{
cout << "in cstor" << endl;
}
my_pair(const my_pair& copy) : foo(copy.foo), bar(copy.bar)
{
cout << "in copy cstor" << endl;
}
然后行为改变:
v.push_back(41, 42); // does not work [f]
v.push_back({41,42}); // displays "in cstor" and "in copy cstor" [g]
v.emplace_back(41,42); // displays "in cstor" [h]
v.emplace_back({41,42}); // does not work [i]
v.emplace_back(my_pair{41,42}); // "in cstor" and "in copy cstor" [j]
如果我添加一个移动构造函数:
my_pair(my_pair&& move_) : foo(move_.foo), bar(move_.bar)
{
cout << "in move cstor" << endl;
}
然后:
v.emplace_back(my_pair{41,42}); //displays "in cstor", "in move cstor" [k]
v.emplace_back({41,42}); // still does not work [l]
v.push_back({41,42}); // displays "in cstor", "in move cstor" [m]
问题:
对于[a,b],我理解工作和不工作的原因。
对于 [c],它不起作用,因为没有构造函数可以将参数转发到。
对于 [d],为什么这不像在 push 情况下那样工作?
对于[e],为什么加了类名就可以了?
对于 [h],如果有一个将参数映射到成员的构造函数,这似乎是最有效的代码
对于 [j],这似乎和 push_back 一样糟糕,而且我不知道为什么有人应该在 push_back 上这样做
对于 [k,m],添加了一个移动构造函数,似乎正在调用 push_back(T&&),这导致与 emplace 相同的性能。但同样,由于额外的输入,我不确定为什么有人会这样做。
我读到 MSVC 没有为您添加移动构造函数: Why is copy constructor called in call to std::vector::emplace_back()?
[d,e] 有什么区别,emplace 为何挑剔。为什么push_back(T&&) 在不添加结构名称的情况下工作?
如果我知道有一个将每个成员作为参数的构造函数,我只能获得 emplace 的全部好处?
我应该坚持使用push_back 吗?是否有任何理由使用emplace_back(structname{1,2,3}) 而不是push_back({1,2,3}),因为它最终会调用push_back(T&&),并且更容易输入?
第三,emplace_back(arg1,arg2,etc),如何施展魔法来完全避免复制或移动构造函数?
【问题讨论】:
-
作为快速评论,
emplace_back({42, 42}通常不起作用,因为它变成了两个整数的initializer-list,而不是my_pair结构。如果您还添加了initializer list构造函数,我认为 emplace_back 调用可能会起作用。当然,有人会认为这会直接解决问题,但是您还必须考虑emplace_back的完美转发语义:在大多数情况下,除非您明确命名类型,否则像emplace_back这样的完美转发函数将采取任何完全按面值给出,没有额外的考虑或转换。
标签: c++ c++11 rvalue-reference