2011-04-12 23 views
6

Prowadzę badania nad stworzeniem własnego ostreamu i wraz z nim, aby obsłużyć bufor dla mojego ostream. Właściwie większość z nich działa, mogę wstawić (< <) do mojego strumienia i uzyskać ciągi bez problemu. Robię to poprzez implikowanie funkcji wirtualnej xsputn. Jednak jeśli wprowadzę (< <) float lub int do strumienia zamiast string xsputn nigdy nie zostanie wywołany.dziedziczenie problemu ostream i streambuf z xsputn i przepełnieniem

Przeszedłem przez kod i widzę, że strumień wywołuje funkcję do_put, a następnie f_put, która ostatecznie próbuje umieścić znak float 1 w buforze. Mogę go wezwać do wywołania mojej implementacji przepełnienia funkcji wirtualnej (int c), jeśli opuszczę mój bufor bez spacji i tym samym otrzymam dane dla float i int.

Teraz jest problem, muszę wiedzieć, kiedy float zostanie umieszczony w buforze. Innymi słowy, muszę wiedzieć, kiedy to ostatni raz, kiedy zostanie przepuszczona konkretna wartość. Powodem, dla którego działa xsputn, jest to, że otrzymuję całą wartość z góry i jej długość. Mogę więc skopiować go do bufora, a następnie wywołać funkcję czekającą na pełny bufor.

Niewątpliwie nadużywam projektu ostream, ponieważ muszę buforować dane wyjściowe, a następnie wysłać je wszystkie naraz dla każdej wprowadzonej wartości (< <).

W każdym razie, aby było jasne, powtórzę to, co robię w inny sposób. Jest bardzo duża szansa, że ​​po prostu źle to wymyślę.

Chcę użyć odziedziczonego ostream i streambuf, aby móc wprowadzić wartości do niego i umożliwić obsługę konwersji typu dla mnie, a następnie chcę przekazać te informacje do innego obiektu, do którego przechodzę uchwyt do the streambuf to (for?). Ten obiekt ma drogie wejścia i wyjścia, więc nie chcę wysyłać danych 1 na raz.

Przepraszam z góry, jeśli to nie jest jasne. I dziękuję za poświęcony czas.

Odpowiedz

13

Nie jest jasne, co robisz, chociaż brzmi mniej więcej prawe. Dla pewności: wszystkie twoje ostream dostarczają wygodnych konstruktorów do stworzenia i zainstalowania destruktora i prawdopodobnie implementacji rdbuf do buforów uchwytów odpowiedniego typu. Przypuśćmy, że to prawda: definiowanie xsputn w twoim streambuf jest czysto optymalizacją. Kluczową funkcją, którą należy zdefiniować, jest overflow. Najprostsza implementacja zajmuje tylko jeden znak, a wyprowadza go do zlewu. Wszystko poza tym jest optymalizacją: możesz, na przykład, ustawić bufor przy użyciu setp; jeśli zrobisz to , wtedy overflow zostanie wywołane tylko wtedy, gdy bufor będzie pełny, lub zostanie zażądany kolor. W tym przypadku będziesz musiał również bufor wyjściowy (użyj pbase i pptr, aby uzyskać adresy ). (Klasa streambuf bazowa inicjuje wskazówek, aby stworzyć bufor 0 długości, więc overflow będzie nazywany dla każdego znaku.) Inne funkcje, które można chcą zastąpić w (bardzo) szczególne przypadki:

imbue: Jeśli Z jakiegoś powodu potrzebujesz ustawienia regionalnego.(Pamiętaj, że aktualne kodowanie znaków jest częścią ustawień narodowych.)

setbuf: Aby umożliwić kodowi klienta określenie bufora. (IMHO, to zwykle nie warto przejmować, ale może masz jakieś szczególne wymagania .)

seekoff: Wsparcie dla poszukujących. Nigdy nie używałem tego w żadnym z my streambuf s, więc nie mogę podać żadnych informacji poza tym, co można przeczytać w standardzie.

sync: wezwał spłukiwania, powinien wypisać dowolne znaki w buforze do zlewu . Jeśli nigdy nie zadzwonisz pod numer setp (więc nie ma bufora ), zawsze jesteś zsynchronizowany i może to być operacja "no-op". overflow lub uflow może zadzwonić pod ten numer, lub oba mogą wywoływać oddzielną funkcję w postaci . (O Jedyna różnica między sync i uflow że uflow zostanie wywołana tylko wtedy, gdy istnieje bufor, i nigdy nie zostanie wywołana, gdy bufor jest pusty. sync zostanie wywołana, gdy kod klienta wypłukuje strumień).

Podczas pisania własnych strumieni, o ile w przeciwnym razie nie zostanie podana wydajność, należy zachować prostotę i zastąpić tylko overflow. Jeśli wydajność dyktuje bufor, ja zazwyczaj umieścić kod do przepłukać buforem do osobnego write(address, length) funkcji i wdrożenie overflow i sync wzdłuż linii od:

int MyStreambuf::overflow(int ch) 
{ 
    if (pbase() == NULL) { 
     // save one char for next overflow: 
     setp(buffer, buffer + bufferSize - 1); 
     if (ch != EOF) { 
      ch = sputc(ch); 
     } else { 
      ch = 0; 
     } 
    } else { 
     char* end = pptr(); 
     if (ch != EOF) { 
      *end ++ = ch; 
     } 
     if (write(pbase(), end - pbase()) == failed) { 
      ch = EOF; 
     } else if (ch == EOF) { 
      ch = 0; 
     } 
     setp(buffer, buffer + bufferSize - 1); 
    } 
    return ch; 
} 

int sync() 
{ 
    return (pptr() == pbase() 
      || write(pbase(), pptr() - pbase()) != failed) 
     ? 0 
     : -1; 
} 

Generalnie nie będę kłopotać się z xsputn, ale jeśli twój klient kodu wyprowadza dużo długich łańcuchów, może to być przydatne. Coś jak to powinno załatwić sprawę:

streamsize xsputn(char const* p, streamsize n) 
{ 
    streamsize results = 0; 
    if (pptr() == pbase() 
      || write(pbase(), pptr() - pbase()) != failed) { 
     if (write(p, n) != failed) { 
      results = n; 
     } 
    } 
    setp(buffer, buffer + bufferSize - 1); 
    return results; 
} 
+0

To, co teraz robię, co chcę wiedzieć, w zasadzie jest, jeśli nie ma w każdym razie powiedzieć, ile razy przepełnienia będzie się nazywać, lub gdy ostatni char nadchodzi. Na przykład jeśli robię mystream << 1.3f; Otrzymam znaki "1", a następnie "." następnie "3", ale wewnątrz streabuf nie mam pojęcia, ile znaków można się spodziewać. A po tym jak dostanę 3, chcę działać na buforze (zadzwoń do innego obiektu, dając mu do zrozumienia, że ​​jest gotowy) –

+2

Nie ma możliwości, aby kod mógł wiedzieć z góry, co zrobi kod klienta, lub ile razy to zrobi. zostanie wezwany. Możesz ustawić 'unitbuf' na' ostream': spowoduje to wywołanie 'sync' na końcu każdego' operatora << '(w destruktorze obiektu' sentry'). Następnie działasz w buforze w 'sync'. –

+0

aha! to jest DOKŁADNIE to, czego potrzebowałem! Zaznaczając to jako odpowiedź, nie możesz jeszcze głosować, wrócę i zrobię to, gdy zdobędę wystarczającą ilość przedstawicieli. Dziękuję bardzo. –