Question

J'essaie d'implémenter un tampon de flux et j'ai du mal à faire overflow() travailler. Je redimensive le tampon par 10 caractères supplémentaires et réinitialise le tampon en utilisant setp. Ensuite, j'incrémente le pointeur en arrière où nous nous sommes arrêtés. Pour une raison quelconque, la sortie n'est pas correcte:

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

Quand j'imprime la chaîne, il sort:

bonjour worl comment ça va?

Il manque le d et le y. Qu'ai-je fait de mal?

Était-ce utile?

La solution

La première chose à ne pas, c'est que vous tirez std::basic_stringbuf<char> pour une raison quelconque sans remplacer toutes les fonctions virtuelles pertinentes. Par exemple, vous ne remplacez pas xsputn() ou sync(): Quelles que soient ces fonctions, vous héritez. Je recommanderais fortement de dériver votre tampon de flux de std::basic_streambuf<char> Au lieu!

La overflow() La méthode annonce un tampon qui est un caractère plus petit que la chaîne du tampon de flux: &buffer.back() n'est pas un pointeur vers la fin du tableau mais vers le dernier caractère de la chaîne. Personnellement, j'utiliserais

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

Il n'y a pas de problème jusqu'à présent. Cependant, après avoir fait de la place pour plus de personnages, vous avez omis d'ajouter le caractère débordant, c'est-à-dire que l'argument a passé overflow() au tampon:

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

Il y a quelques autres petites choses qui ne sont pas tout à fait correctes:

  1. C'est généralement une mauvaise idée de donner un versement virtual Fonctionne un paramètre par défaut. La fonction de classe de base fournit déjà la valeur par défaut et la nouvelle valeur par défaut n'est ramassée que lorsque la fonction est jamais appelée explicitement.
  2. La chaîne renvoyée peut contenir un certain nombre de caractères nuls à la fin car la chaîne maintenue est en fait plus grande que la séquence qui a été écrite jusqu'à présent à moins que le tampon soit exactement plein. Vous devriez probablement implémenter le str() fonction différemment:

    std::basic_string<charT> str() const
    {
        return this->buffer.substr(0, this->pptr() - this->pbase());
    }
    
  3. La croissance de la chaîne par une valeur constante est un problème de performance majeur: le coût de l'écriture n Les personnages sont n * n. Pour plus grand n (Ils n'ont pas vraiment besoin de devenir énormes) Cela causera des problèmes. Vous feriez beaucoup mieux de développer votre buffer De façon exponentielle, par exemple, le doubler à chaque fois ou la croissance d'un facteur de 1.5 Si vous sentez que doubler n'est pas une bonne idée.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top