2011-04-12 16 views
6

Ho fatto ricerche per creare il mio ostream e insieme uno streambuf per gestire il buffer per il mio ostream. In realtà ho quasi tutto funzionante, posso inserire (< <) nel mio stream e ottenere stringhe senza problemi. Lo faccio implorando la funzione virtuale xsputn. Tuttavia se inserisco (< <) un float o un int allo stream invece di una stringa xsputn non viene mai chiamato.ereditando il problema ostream e streambuf con xsputn e overflow

Ho attraversato il codice e vedo che lo stream chiama do_put, quindi f_put che alla fine prova a mettere il carattere float 1 alla volta nel buffer. Posso richiamare la mia implementazione dell'overflow della funzione virtuale (int c) se lascio il mio buffer senza spazio e quindi ottengo i dati per il float e l'int.

Ora questo è il problema, ho bisogno di sapere quando il float è finito messo nel buffer. O per dirla in un altro modo, ho bisogno di sapere quando questa è l'ultima volta che verrà chiamato un overflow per un determinato valore in streaming. Il motivo per cui xsputn funziona per me è perché ottengo l'intero valore in anticipo e la sua lunghezza. Quindi posso copiarlo nel buffer quindi richiamare la funzione in attesa che il buffer sia pieno.

Sto abusando del disegno ostream in quanto devo memorizzare nella cache l'output e quindi inviarlo tutto in una volta per ogni valore immesso (< <).

In ogni caso per essere chiari, ripeterò quello che sto girando in un altro modo. C'è una buona possibilità che io stia solo andando nel modo sbagliato.

Desidero utilizzare un ostream e streambuf ereditato in modo da poter immettere valori in esso e consentirgli di gestire la conversione del tipo per me, quindi voglio trasferire tali informazioni a un altro oggetto che sto passando a un handle in basso lo streambuf a (per?). Quell'oggetto ha un costoso I/O, quindi non desidero inviare i dati 1 carattere alla volta.

Ci scusiamo in anticipo se questo non è chiaro. E grazie per il tuo tempo.

risposta

13

Non è troppo chiaro cosa si sta facendo, anche se suona approssimativamente a destra. Per sicurezza: tutto il tuo ostream fornisce i costruttori di convenienze per creare e installare il tuo streambuf, un distruttore e possibilmente un'implementazione di rdbuf in gestire i buffer del tipo corretto. Supponendo che sia vero: definire xsputn nel tuo streambuf è puramente un ottimizzazione. La funzione chiave che è necessario definire è overflow. La più semplice implementazione di overflow richiede solo un singolo carattere e lo invia al sink. Tutto ciò che va oltre l'ottimizzazione: è possibile, ad esempio, impostare un buffer utilizzando setp; se si esegue questo, quindi overflow verrà chiamato solo quando il buffer è pieno o è stato richiesto uno svuotamento. In questo caso, sarà necessario anche il buffer di output (utilizzare pbase e pptr per ottenere gli indirizzi ). (La classe streambuf di base inizializza i puntatori per creare un buffer 0 lunghezza, in modo overflow sarà chiamato per ogni personaggio.) Altre funzioni che si potrebbe voler ignorare a (molto) casi specifici:

imbue: Se hai bisogno del locale per qualche motivo.Ricordare che la codifica dei caratteri correnti fa parte delle impostazioni internazionali.

setbuf: per consentire al codice client di specificare un buffer. (IMHO, è di solito non vale il fastidio, ma potrebbe essere esigenze particolari.)

seekoff: Supporto per la ricerca. Non l'ho mai usato in nessuno dei miei streambuf s, quindi non posso fornire alcuna informazione oltre a quello che potresti leggere nello standard.

sync: chiamato su flush, deve restituire qualsiasi carattere nel buffer nel sink. Se non chiami mai setp (quindi non c'è il buffer ), sei sempre sincronizzato e questo può essere un no-op. overflow o uflow può chiamare questo, o entrambi possono chiamare qualche funzione separata . (L'unica differenza tra sync e uflow è che uflow sarà chiamato solo se c'è un buffer, e non sarà mai chiamato se il buffer è vuoto. sync sarà chiamato, se il codice client svuota il torrente.)

Quando si scrivono i miei flussi personali, a meno che le prestazioni non dettino altrimenti, lo terrò semplice e sostituirò solo overflow. Se le prestazioni impone un buffer, io di solito metto il codice per filo buffer in un separato write(address, length) funzione e implementare overflow e sync lungo le linee di :

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; 
} 

Generalmente, non sarò disturbare con xsputn, ma se il codice del client emette un sacco di stringhe lunghe, potrebbe essere utile. Qualcosa del genere dovrebbe fare il trucco:

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

che è fondamentalmente ciò che sto facendo ora, quello che voglio sapere è se v'è comunque per dirvi quante volte troppo pieno sta per essere chiamato, o quando l'ultimo il char sta arrivando. Ad esempio, se eseguo mystream << 1.3f; Otterrò i caratteri '1' quindi '.' poi '3' ma dentro lo streabuf non ho modo di sapere quanti personaggi aspettarsi. E dopo aver ottenuto il 3 voglio agire sul buffer (richiamo su un altro oggetto facendogli sapere che è pronto) –

+2

Non c'è modo in cui il codice possa sapere in anticipo che cosa farà il codice client, o quante volte esso sta per essere chiamato. Quello che puoi fare è impostare 'unitbuf' su' ostream': questo farà sì che 'sync' sia chiamato alla fine di ogni' operatore << '(nel distruttore dell'oggetto' sentry'). Quindi agisci sul buffer in 'sync'. –

+0

aha! questo è ESATTAMENTE quello di cui avevo bisogno! Segnando questa come risposta, non posso ancora votare, tornerò e lo farò una volta che avrò abbastanza rep. Grazie mille. –