Оптимизация возвращаемого значения с помощью std::pair

В настоящее время я весьма озадачен гарантированным RVO в C++17 и его последствиями. Я понимаю, что для NRVO, я должен убедиться, что

  1. вернуть один и тот же экземпляр объекта через все возможные пути возврата функции и

  2. инициализировать связанный объект с помощью вызова функции на стороне вызова

Рассмотрим самый простой оформленный класс 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 когда тебе это не нужно.

Другие вопросы по тегам