Pregunta

Estoy tratando de implementar un búfer de transmisión y tengo problemas para hacer overflow() trabajar. Dimite el tamaño del búfer por 10 caracteres más y restablece el búfer usando setp. Luego incremento el puntero donde lo dejamos. Por alguna razón, la salida no es correcta:

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

Cuando imprimo la cadena sale como:

hola worl como estan?

Le falta el d y el y. ¿Qué hice mal?

¿Fue útil?

Solución

Lo primero que no es no es que estés derivando de std::basic_stringbuf<char> por alguna razón sin anular todas las funciones virtuales relevantes. Por ejemplo, no anulas xsputn() o sync(): Cualquiera que sea que estas funciones terminen haciendo, heredarás. Recomiendo encarecidamente derivar su búfer de flujo de std::basic_streambuf<char> ¡en cambio!

los overflow() El método anuncia un búfer que es un personaje más pequeño que la cadena al búfer de transmisión: &buffer.back() No es un puntero al final de la matriz sino al último carácter de la cadena. Personalmente, usaría

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

No hay problema hasta ahora. Sin embargo, después de hacer espacio para más personajes, omitiste agregar el personaje desbordante, es decir, el argumento pasó a overflow() al búfer:

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

Hay algunas pequeñas cosas más que no son del todo correctas:

  1. Generalmente es una mala idea dar anulación virtual Funciona un parámetro predeterminado. La función de clase base ya proporciona el valor predeterminado y el nuevo valor predeterminado solo se recoge cuando la función se llama explícitamente.
  2. La cadena devuelta puede contener una serie de caracteres nulos al final porque la cadena retenida es en realidad más grande que la secuencia que se escribió hasta ahora a menos que el búfer esté exactamente lleno. Probablemente debería implementar el str() funcionar de manera diferente:

    std::basic_string<charT> str() const
    {
        return this->buffer.substr(0, this->pptr() - this->pbase());
    }
    
  3. El crecimiento de la cadena por un valor constante es un problema de rendimiento importante: el costo de la escritura n Los personajes son n * n. Para más grande n (Realmente no necesitan ser enormes) Esto causará problemas. Eres mucho mejor al cultivar tu buffer exponencialmente, por ejemplo, duplicarlo cada vez o crecer por un factor de 1.5 Si sientes que duplicar no es una buena idea.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top