Я использую 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], почему это не работает в случае нажатия?
для [e], почему он работает при добавлении имени класса?
для [h], кажется, что это самый эффективный код, если есть конструктор, который отображает аргументы членам
для [j], похоже, что это так плохо, как push_back, и с дополнительным набором текста я не уверен, почему кто-то должен это делать через push_back
для [k, m], с добавлением конструктора перемещения кажется, что push_back(T&&)
вызывается, что приводит к той же производительности, что и emplace. Но опять же, с дополнительной типизацией, я не уверен, почему кто-то это сделает.
Я прочитал, что MSVC не добавляет для вас конструктор перемещения: Почему конструктор копирования вызван в вызов std::vector:: emplace_back()?
В чем разница между [d, e] и почему это связано с этим. И почему 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)
, сделать свою магию, чтобы полностью избежать копирования или перемещения конструктора?