Оптимизация возвращаемого значения с помощью std::pair
В настоящее время я весьма озадачен гарантированным RVO в C++17 и его последствиями. Я понимаю, что для NRVO, я должен убедиться, что
вернуть один и тот же экземпляр объекта через все возможные пути возврата функции и
инициализировать связанный объект с помощью вызова функции на стороне вызова
Рассмотрим самый простой оформленный класс Widget, и я хочу выделить пару виджетов без копий, а затем вернуть его
#include<iostream>
#include<utility>
struct Widget {
Widget() { std::cerr << "Default ctor" << std::endl; }
explicit Widget(int i) { std::cerr << "custom ctor" << std::endl; }
Widget(Widget const &) { std::cerr << "copy ctor" << std::endl; }
Widget(Widget &&) { std::cerr << "move ctor" << std::endl; }
Widget &operator=(Widget const &) { std::cerr << "copy assign" << std::endl; }
Widget &operator=(Widget &&) { std::cerr << "move assign" << std::endl; }
int i_;
};
auto foo(){
std::pair<Widget,Widget> w; // default construction
auto &[w1,w2] = w;
// do something with w1 and w2
return w;
}
int main(){
auto f = foo();
}
Копия не сделана, но сейчас я попытался использовать make_pair
auto foo(){
auto w = std::make_pair<Widget,Widget>({},{}); // Awkward syntax and move construction
auto &[w1,w2] = w;
// do something with w1 and w2
return w;
}
Это действительно единственно возможная альтернатива, если я хочу использовать make_pair? Есть ли какая-то причина в том, что по сравнению с первой функцией задействована конструкция перемещения?
1 ответ
Я думаю, что предпосылка вашего вопроса неверна.
Это действительно единственно возможная альтернатива, если я хочу использовать make_pair?
Почему вы используете std::make_pair
Вот?
auto w = std::make_pair<Widget,Widget>({},{}); // Awkward syntax and move construction
Это действительно неловкий синтаксис. Позвольте мне объяснить, почему я так думаю...
Из ссылки на std::make_pair
(подчеркните мой):
Создает объект std::pair, выводя целевой тип из типов аргументов.
Единственная цель std::make_pair
заключается в выводе типов его аргументов, как, например, в
std::pair<int,int> x;
x = std::pair<int,int>(3,3); // not nice
x = std::make_pair(3,3); // ok
Когда по умолчанию создается пара и вы знаете ее тип, вам никогда не приходилось повторять параметры шаблона
std::pair<int,int> a = std::pair<int,int>(); // awkward
Ни когда вы хотите конструкцию не по умолчанию (просто не используйте auto
когда его единственным эффектом является то, что вы должны записать тип в другом месте в той же строке кода)
std::pair<int,int> a{5,4}; // no move/copy
Нижняя линия:
Альтернатива просто не использовать std::make_pair
когда тебе это не нужно.