Почему хелпер std :: tuple возвращает значение rvalue вместо значения

Если вы посмотрите наget, вспомогательная функция дляstd::tuple, вы заметите следующую перегрузку:

template< std::size_t I, class... Types >
constexpr std::tuple_element_t<I, tuple<Types...> >&&
get( tuple<Types...>&& t );

Другими словами, он возвращает ссылку на rvalue, когда входной кортеж сам является ссылкой на rvalue. Почему бы не вернуть по значению, позвонивmove в теле функции? Мой аргумент таков: возвращение get будет связано либо со ссылкой, либо со значением (я полагаю, это может быть связано ни с чем, но это не должно быть распространенным случаем использования). Если он привязан к значению, то в любом случае произойдет построение перемещения. Таким образом, вы ничего не теряете, возвращаясь по значению. Если вы привязываетесь к ссылке, то возвращение ссылки на rvalue может быть небезопасным. Чтобы показать пример:

struct Hello {
  Hello() {
    std::cerr << "Constructed at : " << this << std::endl;
  }

  ~Hello() {
    std::cerr << "Destructed at : " << this << std::endl;
  }

  double m_double;
};

struct foo {
  Hello m_hello;
  Hello && get() && { return std::move(m_hello); }
};

int main() {
  const Hello & x = foo().get();
  std::cerr << x.m_double;
}

При запуске эта программа печатает:

Constructed at : 0x7ffc0e12cdc0
Destructed at : 0x7ffc0e12cdc0
0

Другими словами, х - это сразу свисающая ссылка. Тогда как, если вы только что написали foo, вот так:

struct foo {
  Hello m_hello;
  Hello get() && { return std::move(m_hello); }
};

Эта проблема не возникнет. Кроме того, если вы затем используете foo следующим образом:

Hello x(foo().get());

Не похоже, что есть какие-либо дополнительные издержки, независимо от того, возвращаете ли вы значение или ссылку на rvalue. Я тестировал такой код, и кажется, что он будет достаточно последовательно выполнять только одно движение. Например. если я добавлю участника:

  Hello(Hello && ) { std::cerr << "Moved" << std::endl; }

И я создаю x, как указано выше, моя программа печатает «Moved» только один раз, независимо от того, возвращаю ли я значение или ссылку на rvalue.

Есть ли веская причина, по которой я скучаю, или это упущение?

Примечание: здесь есть хороший связанный вопрос:Возвращаемое значение или ссылка на значение?, Кажется, говорят, что возвращение значения обычно предпочтительнее в этой ситуации, но тот факт, что он обнаруживается в STL, вызывает у меня любопытство, проигнорировал ли STL это рассуждение, или у них есть свои собственные особые причины, которые могут быть не применимыми в общем-то.

Редактировать: кто-то предложил этот вопрос является дубликатомЕсть ли случай, когда возврат ссылки RValue (&&) полезен?, Это не вариант; этот ответ предполагает возврат по rvalue-ссылке как способ точного копирования элементов данных. Как я подробно обсудил выше, копирование будет исключено независимо от того, вернетесь ли вы по значению или по rvalue, если вы позвонитеmove первый.

Ответы на вопрос(1)

Ваш ответ на вопрос