Я хотел бы считать некоторые данные с потока, у меня есть использование std::getline
. Ниже образца с помощью std::cin
.
std::string line;
std::getline( std::cin, line );
Это - блокирующаяся функция т.е. при отсутствии данных или строки для чтения, она блокирует выполнение.
Вы знаете, существует ли функция для проверки доступности данных перед вызовом std::getline
? Я не хочу блокироваться.
Как я могу проверить, полон ли потоковый буфер данных, допустимых для успешного вызова к std::getline
?
Независимо от того, что похоже на код ниже
if( dataAvailableInStream() )
{
std::string line;
std::getline( std::cin, line );
}
Библиотека iostream
не поддерживает концепцию неблокирующего ввода/вывода. Я не думаю, что в стандарте C++ есть что-то, что поддерживает. Любое хорошее решение, скорее всего, будет специфичным для конкретной платформы. Если вы можете использовать библиотеки POSIX, вы можете посмотреть на select
. Обычно он используется для сетевых задач, но он будет работать, если вы передадите ему дескриптор файла для stdin.
Не существует стандартного способа проверить, блокируется ли getline
. Вы можете использовать:
std::cin.rdbuf()->in_avail()
, чтобы узнать, сколько символов определенно доступно до того, как операция чтения может быть заблокирована, но вам придется читать символы один за другим перед повторной проверкой in_avail
, поскольку нет возможности заранее узнайте, является ли какой-либо из ожидающих символов новой строкой или фактическим концом потока. В противном случае вызов getline
может заблокироваться.
Обратите внимание, что хотя если in_avail ()
возвращает положительное число, гарантируется, что до конца потока доступно по крайней мере такое количество символов, обратное неверно. Если in_avail ()
возвращает ноль, символы все еще могут быть доступны, и поток может не блокироваться немедленно.
std :: iostream предоставляет функцию просмотра, которая возвращает следующий символ в потоке, не удаляя его. Таким образом, вы можете сделать что-то вроде следующего (полностью не проверено).
bool dataAvailableInStream( std::iostream &stream )
{
return stream.peek() != std::iostream::traits_type::eof();
}
Править
Как указывает rubenvb, std :: cin
блокируется по замыслу. Таким образом, приведенный выше код поможет вам обойти блокировку getline
, но не cin
.
Править Править
Как Чарльз указывает ниже, просматривает
блоки, если данные недоступны. Следовательно, это не дает полного решения. Это убережет вас от блокировки на getline
, но не от блокировки в целом.
Хотя ответ nathan peek ()
покажет, есть ли данные, нет никакой гарантии, что std :: getline ()
будет успешным в чтение «строчки».
Всегда намного проще, хотя и немного назад, попробовать getline и проверить результат самого вызова функции:
std::string line;
while( !std::getline(std::cin, line) )
{
cout << "Enter something please" << endl;
}
Этот код будет работать до тех пор, пока cin
не получит то, что ему нравится (т.е. сможет извлечь и разместить в строке
). Я не считаю, что peek ()
здесь необходим или полезен.
РЕДАКТИРОВАТЬ: Дело в том, что cin
(== стандартный ввод с клавиатуры) должен будет заблокировать программу, пока она ожидает ввода, как еще она может получить какой-либо ввод, если она не будет ждать?
Какую проблему вы пытаетесь решить, избегая блокировки чтения здесь?
Непереносимость Я полагаю, вы могли бы использовать poll
или select
чтобы узнать, есть ли данные для чтения на stdin (часто fd 0 в системах unix).
В качестве альтернативы вы можете создать второй поток для выполнения операций ввода-вывода и просто позволить ему блокироваться, чтобы вы могли продолжить нормальную обработку в основном потоке.