Domanda

Sto cercando di implementare un buffer di streaming e ho problemi a fare overflow() opera. Ridimio il buffer di altri 10 caratteri e reimposto il buffer utilizzando setp. Quindi aumento il puntatore da dove abbiamo lasciato. Per qualche motivo l'output non è giusto:

template <class charT, class traits = std::char_traits<charT>>
class stringbuf : public std::basic_stringbuf<charT, traits>
{
public:
    using char_type   = charT;
    using traits_type = traits;
    using int_type    = typename traits::int_type;
public:
    stringbuf()
        : buffer(10, 0)
    {
        this->setp(&buffer.front(), &buffer.back());
    }

    int_type overflow(int_type c = traits::eof())
    {
        if (traits::eq_int_type(c, traits::eof()))
            return traits::not_eof(c);

        std::ptrdiff_t diff = this->pptr() - this->pbase();

        buffer.resize(buffer.size() + 10);
        this->setp(&buffer.front(), &buffer.back());

        this->pbump(diff);

        return traits::not_eof(traits::to_int_type(*this->pptr()));
    }
    // ...
    std::basic_string<charT> str()
    {
        return buffer;
    }
private:
    std::basic_string<charT> buffer;
};

int main()
{
    stringbuf<char> buf;
    std::ostream os(&buf);

    os << "hello world how are you?";
    std::cout << buf.str();
}

Quando stampa la stringa viene fuori come:

ciao worl come stai?

Manca il d e il y. Cos'ho fatto di sbagliato?

È stato utile?

Soluzione

La prima cosa da no è che stai derivando std::basic_stringbuf<char> Per qualsiasi motivo senza prevalere su tutte le funzioni virtuali pertinenti. Ad esempio, non sovrascrivi xsputn() o sync(): Qualunque cosa queste funzioni finiscano per fare, erediterai. Consiglio vivamente di derivare il tuo buffer di streaming std::basic_streambuf<char> invece!

Il overflow() Il metodo annuncia un buffer che è un carattere più piccolo della stringa al buffer del flusso: &buffer.back() non è un puntatore alla fine dell'array ma all'ultimo carattere nella stringa. Personalmente, lo userei

this->setp(&this->buffer.front(), &this->buffer.front() + this->buffer.size());

Finora non ci sono problemi. Tuttavia, dopo aver fatto spazio per più personaggi che hai omesso aggiungendo il personaggio traboccante, cioè l'argomento passato a overflow() al buffer:

this->pbump(diff);
*this->pptr() = traits::to_char_type(c);
this->pbump(1);

Ci sono alcune altre piccole cose che non hanno ragione:

  1. È generalmente una cattiva idea dare prevalente virtual Funzioni un parametro predefinito. La funzione di classe base fornisce già il valore predefinito e il nuovo impostazione predefinita viene raccolto solo quando la funzione viene mai chiamata esplicitamente.
  2. La stringa restituita può contenere un numero di caratteri null alla fine perché la stringa trattenuta è in realtà più grande della sequenza che è stata scritta finora a meno che il buffer non sia esattamente pieno. Probabilmente dovresti implementare il str() funzione in modo diverso:

    std::basic_string<charT> str() const
    {
        return this->buffer.substr(0, this->pptr() - this->pbase());
    }
    
  3. Crescere la stringa di un valore costante è un grave problema di prestazioni: il costo della scrittura n i personaggi sono n * n. Per più grande n (Non hanno davvero bisogno di diventare enormi) Questo causerà problemi. Stai molto meglio a far crescere il tuo buffer esponenzialmente, ad esempio, raddoppiandolo ogni volta o crescere di un fattore di 1.5 Se ti senti raddoppiare non è una buona idea.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top