2016-08-17 10 views
0

Проблема заключается в следующем: я пишу пользовательский буферизованный поток ввода, который считывает строки в кусках определенного размера, которые необходимо преобразовать (различные способы: измененные символы, целые куски пропущены, если определенный контент найден и т. Д.). , Трансформация сама по себе не имеет значения, потому что я застрял в понимании вклада вообще. Вот код (на основе из https://stackoverflow.com/a/14086442/3651664):Пользовательский буферный входной поток. Конец ввода

#include <fstream> 
#include <iostream> 
#include <cstring> 

class skipchar_stream_buffer: public std::streambuf 
{ 
private: 
    char* m_buffer; 
    std::streambuf* m_stream_buffer; 
    std::streamsize m_size; 
public: 
    skipchar_stream_buffer(std::streambuf* stream_buffer); 
    virtual ~skipchar_stream_buffer(); 
    virtual std::streambuf::int_type underflow(); 
}; 

skipchar_stream_buffer::skipchar_stream_buffer(std::streambuf* stream_buffer) 
{ 
    m_size = 10; 
    m_buffer = new char[m_size](); 
    m_stream_buffer = stream_buffer; 
} 

skipchar_stream_buffer::~skipchar_stream_buffer() 
{ 
    delete[] m_buffer; 
} 

std::streambuf::int_type skipchar_stream_buffer::underflow() 
{ 
    std::memset(m_buffer, 0, m_size); 

    std::streamsize read = m_stream_buffer->sgetn(m_buffer, m_size); 

    setg(m_buffer, m_buffer, m_buffer + m_size); 

    std::cout << "buffer = '" << m_buffer << "'" << std::endl; 

    if (gptr() == egptr()) 
    return traits_type::eof(); 
    else 
    return traits_type::to_int_type(*gptr()); 
} 

class skipchar_istream: public std::istream 
{ 
public: 
    skipchar_istream(std::istream& stream); 
    virtual ~skipchar_istream(); 
}; 

skipchar_istream::skipchar_istream(std::istream& stream) : 
    std::istream(new skipchar_stream_buffer(stream.rdbuf())) 
{ 

} 

skipchar_istream::~skipchar_istream() 
{ 
    delete rdbuf(); 
} 

int main() 
{ 
    char s[32]; 

    skipchar_istream in(std::cin); 
    in >> s; 
    std::cout << s; 

    return 0; 
} 

И вопрос: зачем мне нужно явно завершить ввод (путем отправки EOF, например)? Почему нажимать enter недостаточно? Или я вообще делаю это совершенно неправильно? Работа в VS2010.


Обновление: Найдено еще одна проблема с этим кодом: если поставляется количество символов не кратно размеру буфера, underflow метод не вызывается автоматически (только один раз при первом). Почему это? Неправильно ли с настройками указателя в setg?

ответ

1

Нажатие Enter отправляет символ в буфер ввода/вывода. Это не означает «конец ввода». В файле вы можете легко иметь что-то вроде

Dear Mr. Smith,<CR><EOL>I am writing to you this message.<CR><EOL>Kind regards,<CR><EOL>Your Name<EOF> 

Стандартный поток дает вам большую гибкость в том, как читать этот вход.

Например:

istream get() will return you 'D' 
istream operator >> will return "Dear" 
istream getline() will return "Dear Mr. Smith," 
streambuf sgetn (6) will return "Dear M" 

Вы можете также корректировать свое поведение с вашими потребностями. Таким образом, вы можете читать столько или меньше, сколько хотите.

В коде чтение операция:

std::streamsize read = m_stream_buffer->sgetn(m_buffer, m_size); 

, что означает «дать мне m_size символов или меньше, если конец ввода произошло». Посмотрите на документацию streambuf для лучшего объяснения. http://www.cplusplus.com/reference/streambuf/streambuf

std :: streambuf работает на основе каждого символа. Нет getline() или оператора >> здесь. Если вы хотите остановиться у определенного символа (например,), вам, вероятно, понадобится цикл с sgetc().

+0

Хорошо. Хотя я все еще не понимаю, что случилось. Используемый поток ввода получается из 'istream', например, как' cin'. И 'cin' останавливается на новой линии. Что мне делать? – HighPredator

+1

«остановки на новой линии» реализованы в cin. Вы должны написать это самостоятельно .. – Sergei

+0

Понял, спасибо. – HighPredator