2016-05-06 11 views
10

Я бы хотел скопировать данные эффективно между std::streambuf экземпляров. То есть, я хотел бы сгребать блоки данных между ними, а не выполнять копирование по одному символу. Например, это не то, что я ищу:Блочное копирование данных между потоковыми буферами

stringbuf in{ios_base::in}; 
stringbuf out{ios_base::out}; 
copy(istreambuf_iterator<char>{in}, 
    istreambuf_iterator<char>{}, 
    ostreambuf_iterator<char>{out}); 

Там существует синтаксический сахар для этого, с немного больше контроля ошибок:

ostream os{&out}; 
os << &in; 

Вот фрагмент реализации operator<<(basic_streambuf<..>*) в моей стандартной библиотеки (Mac OS X, XCode 7):

   typedef istreambuf_iterator<_CharT, _Traits> _Ip; 
       typedef ostreambuf_iterator<_CharT, _Traits> _Op; 
       _Ip __i(__sb); 
       _Ip __eof; 
       _Op __o(*this); 
       size_t __c = 0; 
       for (; __i != __eof; ++__i, ++__o, ++__c) 
       { 
        *__o = *__i; 
        if (__o.failed()) 
         break; 
       } 

Суть: это по-прежнему за характер копирования. Я надеялся, что стандартная библиотека использует алгоритм, который опирается на функции-элементы уровня блока потоковых буферов, sputn и sgetn, в отличие от транспорта на один символ. Предоставляет ли стандартная библиотека такой алгоритм, или мне нужно сворачивать самостоятельно?

+3

Проблема заключается в том, что это основано на интерфейс с виртуальными функциями. Вы никогда не знаете, когда '* __ o = * __ i' не будет выводиться, поэтому вы не можете читать дальше и рискуете потерять эти символы. –

+0

Вы нашли способ? – barney

ответ

1

Я боюсь, что ответ таков: это невозможно с нынешним дизайном стандартной библиотеки. Причина в том, что потоковые буфферы полностью скрывают последовательность символов, которыми они управляют. Это делает невозможным непосредственное копирование байтов из области получения одного streambuffer в область сложения другого.

Если «поток» streambuffer будет выставлять свой внутренний буфер, тогда «выходной» потоковый буффер может просто использовать sputn(in.data(), in.size()). Или, что более очевидно: если выходной буфер также выставил свой внутренний буфер, то можно было бы использовать простой memcpy для перекоса байтов между ними. Другие библиотеки ввода-вывода работают следующим образом: например, stream implementation буферов протокола Google. Boost IOStreams имеет optimized implementation to copy between streams. В обоих случаях эффективное блочное копирование возможно, потому что эквивалент streambuffer обеспечивает доступ к его промежуточному буферу.

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

  1. чтение из входного streambuffer с помощью sgetn в промежуточный буфер.
  2. Запись из промежуточного буфера в выходной поток буферизатора через sputn.
  3. Перейти к 1. пока вход не будет исчерпан или записывает на выход streambuffer строя