Что не так с моей реализацией overflow()?
Я пытаюсь реализовать буфер потока, и у меня возникают проблемы с созданием overflow()
Работа. Я изменяю размер буфера еще на 10 символов и сбрасываю буфер, используя setp
, Затем я увеличиваю указатель туда, где мы остановились. По какой-то причине вывод не правильный:
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();
}
Когда я печатаю строку, она выглядит так:
привет, как дела?
Это не хватает d
и y
, Что я сделал не так?
1 ответ
Первое, что не нужно, это то, что вы производите от 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);
Есть еще несколько мелочей, которые не совсем верны:
- Обычно плохая идея давать переопределение
virtual
работает параметр по умолчанию. Функция базового класса уже обеспечивает значение по умолчанию, и новое значение по умолчанию выбирается только тогда, когда функция вызывается явно. Возвращаемая строка может содержать количество нулевых символов в конце, потому что удерживаемая строка на самом деле больше, чем последовательность, которая была записана до тех пор, пока буфер не будет полностью заполнен. Вы, вероятно, должны реализовать
str()
функционировать по-разному:std::basic_string<charT> str() const { return this->buffer.substr(0, this->pptr() - this->pbase()); }
- Увеличение строки на постоянное значение является основной проблемой производительности: стоимость написания
n
символыn * n
, Для большегоn
(им действительно не нужно становиться огромными) это вызовет проблемы. Вы гораздо лучше выращиваетеbuffer
экспоненциально, например, удваивая его каждый раз или увеличивая в1.5
если ты чувствуешь удвоение, это не очень хорошая идея.