Разумно ли взять std :: istream & amp; & amp; в качестве аргумента?

Я сделал то, что сказал CamHart:

import sys
def myFunctionsHere():
    print(sys._getframe().f_code.co_name)

myFunctionsHere()

Выход:

C: \ Python \ Python36 \ python.exe C: / Python / GetFunctionsNames / TestFunctionsNames. py myFunctionsHere

Процесс завершен кодом выхода 0

8
задан spraff 16 January 2019 в 15:56
поделиться

4 ответа

Ваше предположение о том, что ссылочный параметр rvalue подразумевает «вступление во владение», совершенно неверно. Ссылка Rvalue - это просто особая ссылка, которая поставляется с собственными правилами инициализации и правилами разрешения перегрузки. Не больше, не меньше. Формально он не имеет особого сходства с «перемещением» или «захватом» объекта, на который имеется ссылка.

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

Пример цитаты, похожей на ту, которую вы только что цитировали, фактически присутствует в самой стандартной библиотеке. Это дополнительные перегрузки, введенные в C ++ 11 (и C ++ 17, в зависимости от некоторых нюансов)

template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os, 
                                            const T& value );

template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>&& st, T&& value );

Их основная цель - «преодолеть» разницу в поведении между членами и не перегрузки элементов в operator <<

#include <string>
#include <sstream>

int main() 
{
  std::string s;
  int a;

  std::istringstream("123 456") >> a >> s;
  std::istringstream("123 456") >> s >> a;
  // Despite the obvious similarity, the first line is well-formed in C++03
  // while the second isn't. Both lines are well-formed in C++11
}

Он использует тот факт, что ссылка на rvalue может связываться с временными объектами и все еще видеть их как изменяемые объекты. В этом случае ссылка rvalue используется в целях, которые не имеют ничего общего с семантикой перемещения. Это совершенно нормально.

0
ответ дан AnT 16 January 2019 в 15:56
поделиться

std::istream не является подвижным , так что практической пользы для этого нет.

Это уже сигнализирует о том, что вещь может быть «модифицирована», не путаясь с предположением, что вы передаете право собственности на объект std::istream (что вы не делаете и не можете сделать).

Я могу отчасти увидеть обоснование использования этого, чтобы сказать, что поток логически перемещается, но я думаю, что вы должны провести различие между «владением этой вещью передается», и «Я сохраняю право собственности на эту вещь, но я позволю вам использовать все ее услуги». Передача прав собственности довольно хорошо понимается как соглашение в C ++, и это не совсем так. Что подумают пользователи вашего кода, когда им придется написать parse(std::move(std::cin))?

Хотя ваш путь не «опасен»; вы не сможете ничего сделать с этой ссылкой на rvalue, что вы не сможете сделать с ссылкой на lvalue.

Было бы гораздо более самодокументированным и обычным делом просто взять ссылку на lvalue.

0
ответ дан Lightness Races in Orbit 16 January 2019 в 15:56
поделиться

std::move просто создает ссылку на значение из объекта и ничего более. Природа rvalue такова, что вы можете предположить, что никто не будет заботиться о его состоянии после того, как вы закончите с ним. std::move затем используется, чтобы позволить разработчикам давать обещания об объектах с другими категориями значений. Другими словами, вызов std::move в значимом контексте эквивалентен высказыванию «Я обещаю, что меня больше не волнует состояние этого объекта».

Поскольку вы сделаете объект практически непригодным для использования, и вы хотите убедиться, что вызывающий объект больше не будет использовать объект, использование ссылки на rvalue усиливает это ожидание в некоторой степени. Это заставляет звонящего дать это обещание вашей функции. Невыполнение обещания приведет к ошибке компилятора (при условии, что другой допустимой перегрузки нет). Не имеет значения, действительно ли вы переехали с объекта или нет, только то, что первоначальный владелец согласился утратить его право собственности.

0
ответ дан François Andrieux 16 January 2019 в 15:56
поделиться

То, что вы пытаетесь сделать здесь, не является «опасным» в том смысле, что, учитывая текущий интерфейс std::istream, кажется, что не существует каких-либо обстоятельств, при которых ссылка на rvalue здесь обязательно приведет к неопределенности. поведение при получении ссылки на lvalue не будет иметь. Но семантика всей этой хитроумной штуки ИМХО в лучшем случае очень сомнительна. Что означает для вызывающего кода «отдавать право собственности», но в то же время «не передавать его»? Кто «владеет» потоком после возвращения parse() !? Каким образом parse() делает поток «непригодным для использования»? Что если синтаксический анализ завершится неудачно из-за какой-то ошибки до того, как весь поток будет «потреблен»? Поток "непригоден" тогда !? Никто не может попробовать прочесть остальное? Является ли "право собственности" как-то "возвращено" вызывающему коду в этом случае?

Поток - это абстрактное понятие. Цель абстракции потока - служить интерфейсом, через который кто-то может потреблять ввод, не зная, откуда поступают данные, где они живут или как к ним получают доступ и как ими управлять. Если цель parse() состоит в том, чтобы проанализировать входные данные из произвольных источников, то это не должно касаться природы источника. Если это касается природы источника, то он должен запросить конкретный вид источника. И именно здесь, IMHO, ваш интерфейс противоречит сам себе. В настоящее время parse() использует произвольный источник. Интерфейс говорит: я беру любой поток, который вы мне даете, мне все равно, как он реализован. Пока это поток, я могу работать с ним. В то же время, он требует от вызывающей стороны отказаться от объекта, который фактически реализует поток. Интерфейс требует, чтобы вызывающая сторона передала что-то, что сам интерфейс не позволяет какой-либо реализации за интерфейсом когда-либо знать, получать к ней доступ или использовать любым способом. Например, как бы я прочитал parse() из std::ifstream? Кто потом закрывает файл? Если не может быть парсером. Это также не может быть я, потому что вызов парсера заставил меня передать объект. В то же время я знаю, что синтаксический анализатор даже не мог знать, что он должен был закрыть файл, который я передал…

В конце концов, он все равно будет работать правильно, потому что реализация способа не была реализована. Интерфейс действительно мог сделать то, что предполагал интерфейс, и мой деструктор std::ifstream просто запустит и закроет файл. Но что именно мы получили, лгая друг другу так ?! Вы обещали захватить объект, когда вы никогда не собирались, я обещал никогда не трогать объект снова, когда я знал, что мне всегда придется…

0
ответ дан Michael Kenzel 16 January 2019 в 15:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: