2013-11-07 3 views
1

Я пытаюсь реализовать буфер потока, и у меня возникают проблемы с выполнением работы overflow(). Я изменяю размер буфера еще на 10 символов и сбрасываю буфер с помощью setp. Затем я увеличиваю указатель назад, где мы остановились. По какой-то причине выход не прав:Что случилось с моей реализацией overflow()?

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

При печати строки она выходит как:

привет Worl как же НУ?

Не хватает d и y. Что я сделал не так?

ответ

4

Первым делом не то, что вы получаете от std::basic_stringbuf<char> по любой причине, не переопределяя все соответствующие виртуальные функции. Например, вы не переопределяете xsputn() или sync(): что бы ни выполняли эти функции, вы наследуете. Я бы настоятельно рекомендовал вывести ваш буфер потока с std::basic_streambuf<char> вместо этого!

Метод overflow() объявляет буфер, который является одним символом, меньшим, чем строка, в буфер потока: &buffer.back() не является указателем на конец массива, а последним символом в строке. Лично я бы использовал

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

Нет проблем. Однако, после создания пространства для более символов вы опустили добавив перелив характера, то есть аргумент, переданный overflow() в буфер:

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

Есть еще несколько мелочей, которые не совсем верно:

  1. Как правило, плохая идея дать переопределение virtual функции по умолчанию. Функция базового класса уже предоставляет значение по умолчанию, а новый по умолчанию выбирается только тогда, когда функция вызывается явно.
  2. Возвращаемая строка может содержать несколько нулевых символов в конце, потому что удерживаемая строка на самом деле больше, чем последовательность, которая была написана до тех пор, пока буфер не будет полностью заполнен. Вы, вероятно, следует реализовать str() функцию по-разному:

    std::basic_string<charT> str() const 
    { 
        return this->buffer.substr(0, this->pptr() - this->pbase()); 
    } 
    
  3. Растущий строку постоянным значением является одной из основных проблем производительности: стоимость написания n символов n * n. Для больших n (им действительно не нужно становиться огромным), это вызовет проблемы. Вы намного лучше выращиваете свой buffer экспоненциально, например, удваивая его каждый раз или увеличиваясь в 1.5, если вы чувствуете удвоение - это не очень хорошая идея.
Смежные вопросы