2016-05-06 37 views
10

Chciałbym skutecznie skopiować dane między instancjami std::streambuf. To znaczy, chciałbym przerzucić bloki danych między nimi, w przeciwieństwie do kopiowania znaków po znaku. Na przykład, jest to nie co szukam:Kopiowanie danych na poziomie bloków między streiabossami

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

Istnieje cukier syntaktyczny dla tego, z nieco więcej kontroli błędów:

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

Oto fragment realizacji operator<<(basic_streambuf<..>*) w mojej bibliotece standardowej (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; 
       } 

Najważniejsze jest to: to wciąż za kopiowanie znaku. Miałem nadzieję, że standardowa biblioteka korzysta z algorytmu, który opiera się na blokowych funkcjach składowych filtrów, sputn i sgetn, w przeciwieństwie do transportu na znak. Czy standardowa biblioteka zapewnia taki algorytm, czy też muszę samodzielnie wykonać własną kopię?

+3

Problemem jest to, że opiera się na interfejsie z funkcji wirtualnych. Nigdy nie wiesz, kiedy '* __ o = * __ i' nie powiedzie się, więc nie możesz czytać z wyprzedzeniem i ryzykujesz utratę tych znaków. –

+0

znalazłeś metodę? – barney

Odpowiedz

1

Obawiam się, że odpowiedź brzmi: nie jest to możliwe z bieżącym projektem standardowej biblioteki. Powodem jest to, że streambuffers całkowicie ukrywają sekwencję znaków, którymi zarządzają. Dzięki temu niemożliwe jest bezpośrednie kopiowanie bajtów z obszaru get jednego streambuffera do obszaru put drugiego.

Jeśli "wejściowy" streambuffer ujawni swój wewnętrzny bufor, wówczas "wyjściowy" streamer mógłby po prostu użyć sputn(in.data(), in.size()). Lub bardziej oczywiście: jeśli bufor wyjściowy również ujawnił swój wewnętrzny bufor, wtedy można użyć zwykłego memcpy, aby pobrać bajty między tymi dwoma. Inne biblioteki I/O działają w ten sposób: na przykład stream implementation buforów protokołów Google. Zwiększenie IOStreams ma optimized implementation to copy between streams. W obu przypadkach możliwe jest wydajne kopiowanie na poziomie bloku, ponieważ ekwiwalent streambuffer zapewnia dostęp do jego bufora pośredniego.

W rzeczywistości, streiabuffers ironicznie nie muszą nawet mieć bufora: podczas pracy w niebuforowanym, każdy odczyt/zapis trafia bezpośrednio do podstawowego urządzenia. Prawdopodobnie jest to jeden z powodów, dla których biblioteka standardowa nie obsługuje introspekcji. Niefortunną konsekwencją jest to, że nie jest możliwe wydajne kopiowanie między ramkami wejściowymi i wyjściowymi. kopiowanie na poziomie bloków wymaga bufor pośredniczący, a algorytm kopia działałby następująco:

  1. odczytać z streambuffer wejściowego poprzez sgetn do bufora pośredniczącego.
  2. Zapisywanie z bufora pośredniego do wyjściowego streambuffera przez sputn.
  3. Idź do 1. Do czasu wejścia jest wyczerpany lub pisze do wyjścia streambuffer fail