Почему копирование stringstream запрещено?

#c #stringstream

#c #stringstream

Вопрос:

 int main()
{
   std::stringstream s1("This is my string.");
   std::stringstream s2 = s1; // error, copying not allowed
}
  

Я не смог найти причину, по которой я не могу скопировать stringstream. не могли бы вы предоставить какую-нибудь ссылку?

Комментарии:

1. В случае, если вы не знаете об этом, вы можете эффективно выполнить копирование с помощью std::stringstream s2(s1.str()); .

2. @Space: Я думаю, это было бы более уместно: std::stringstream s2; s2 << s1.rdbuf(); .

3. @GManNickG Не снижает ли это производительность?

4. @StanE: Чем … что? Чем предыдущий комментарий? Я так не думаю. Вам нужно будет измерить, чтобы быть уверенным.

5. @StanE: Единственный способ убедиться — это измерить. 🙂

Ответ №1:

Копирование ЛЮБОГО потока в C отключается путем создания конструктора копирования private .

Любой означает ЛЮБОЙ, будь то stringstream , istream ostream iostream или что-то еще.

Копирование потока отключено, потому что это не имеет смысла. Очень, очень, очень важно понимать, что такое stream, чтобы на самом деле понять, почему копирование stream не имеет смысла. stream — это не контейнер, из которого вы можете сделать копию. Он не содержит данных.

Если список / вектор / карта или любой контейнер является корзиной, то stream — это шланг, по которому протекают данные. Думайте о stream как о некотором канале, через который вы получаете данные; канал — на одной стороне находится источник (отправитель), на другой стороне — приемник (receiver). Это называется однонаправленным потоком. Существуют также двунаправленные потоки, через которые данные протекают в обоих направлениях. Так какой же смысл делать копию такой вещи? Он вообще не содержит никаких данных. Именно через него вы получаете данные.

Теперь предположим на некоторое время, разрешено ли создание копии stream, и вы создали копию std::cin , которая на самом деле является входным потоком. Допустим, скопированный объект является copy_cin . Теперь спросите себя: имеет ли смысл считывать данные из copy_cin потока, когда те же самые данные уже были считаны из std::cin. Нет, это не имеет смысла, потому что пользователь ввел данные только один раз, клавиатура (или устройство ввода) сгенерировала электрические сигналы только один раз, и они проходили через все другие аппаратные средства и низкоуровневые API только один раз. Как ваша программа может прочитать это дважды или более?

Следовательно, создание копии запрещено, но создание ссылки разрешено:

 std::istream  copy_cin = std::cin; //error
std::istream amp; ref_cin = std::cin; //ok
  

Также обратите внимание, что вы можете создать другой экземпляр stream и заставить его использовать тот же базовый буфер, который в настоящее время использует старый stream. Смотрите это :https://ideone.com/rijov

Комментарии:

1. @davka: Буфер, конечно, является общим. Прочитайте из одного, и он будет отсутствовать в другом.

2. Метафора «шланга» хороша, но тогда где заканчиваются те данные, которые я поместил в std::stringstream? К этому шлангу должна быть подключена корзина по умолчанию, поскольку я могу получить содержимое этой корзины, выполнив, например, std::stringstream::str() .

3. Я не понимаю, чем все, что вы говорите, отличается для итераторов и потоков, но вы можете копировать итераторы, но не потоки.

4. @Mehrdad: Дизайн итераторов основан на семантике указателей (указатели — это итераторы, помните?). Вот почему итераторы копируются, потому что указатели копируются! Вы все еще можете выборочно отключить копирование для итераторов определенной категории (скажем, входных итераторов), но это внесло бы сложность и непоследовательность в дизайн. например, итераторы произвольного доступа (такие как указатели) также являются итераторами ввода.

5. Я прекрасно понимаю, почему итераторы можно копировать, я не спрашиваю и не жалуюсь на это. Я говорю, что потоки могли бы копироваться точно таким же образом с точно таким же результатом, но это не так… это означает, что ваш ответ, вероятно, неверен, потому что нет реальной причины, по которой они не могли бы иметь ту же семантику, что и указатели при копировании.

Ответ №2:

Чтобы прямо ответить на вопрос, вы не можете копировать, потому что конструктор копирования для класса stringstream объявлен как private .

Вероятно, это было объявлено таким образом, потому что в большинстве случаев копировать stream кажется неудобным, поэтому ни у одного из классов stream нет открытых конструкторов копирования.

Комментарии:

1. На самом деле, это конструктор копирования для ios_base , который является закрытым, что означает, что любой поток не подлежит копированию.

Ответ №3:

Как упоминалось выше, вы не можете скопировать поток, но при необходимости вы можете скопировать данные:

 std::stringstream from;
std::stringstream to;

std::copy(std::istream_iterator<char>(from), std::istream_iterator<char>(),
          std::ostream_iterator<char>(to));
  

Комментарии:

1. почему бы не использовать s2.str(s1.str()) ?