Почему хелпер 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
первый.