web-dev-qa-db-ja.com

std :: getlineを呼び出す前にデータの可用性を確認する

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ライブラリは、非ブロッキングI/Oの概念をサポートしていません。 C++標準にはそれを行うものは何もないと思います。優れたソリューションは、プラットフォーム固有である可能性があります。 POSIXライブラリを使用できる場合は、 select を調べることができます。これは通常、ネットワーク関連で使用されますが、stdinのファイル記述子を渡せば問題なく機能します。

8

getlineがブロックするかどうかを確認する標準的な方法はありません。次を使用できます。

_std::cin.rdbuf()->in_avail()
_

読み取り操作がブロックされる前に確実に使用可能な文字数を確認しますが、保留中の文字があるかどうかを事前に知る方法がないため、_in_avail_を再確認する前に文字を1つずつ読み取る必要があります。改行またはストリームの実際の終わりです。そうでない場合、getline呼び出しがブロックされる可能性があります。

in_avail()が正の数を返す場合、ストリームの終了前に少なくともその数の文字が使用可能であることが保証されますが、その逆は真ではないことに注意してください。 in_avail()がゼロを返した場合でも、使用可能な文字が残っている可能性があり、ストリームがすぐにブロックされない可能性があります。

17
CB Bailey

このコードは、ブロックせずにstdin内のデータの存在を確認するのに役立ちます。

std::cin.seekg(0, std::cin.end);
int length = std::cin.tellg();
if (length < 0) return; //- no chars available

stdinにデータがある場合は、位置を最初に戻すことを忘れないでください。

std::cin.seekg(0, std::cin.beg);

次に、バッファの最後にある\0(複数の場合があります)を含むすべてのデータを読み取ることができます。

std::vector<char> s(length);
std::cin.read(s.data(), length);

または行ごと:

std::string line;
while (std::cin) {
    std::getline(std::cin, line);
    //.....
}

このコードはMSVCとgcc(Ubuntu)で動作します

4
mr NAE

ハックは、読み取りの前にkbhit()を呼び出すことである可能性があります。おそらく持ち運びできず、危険に満ちています...

#include <conio.h>
#include <iostream>

using namespace std;


char buffer[128];

if (kbhit())
{
     cin.getline(buffer, sizeof(buffer));
}
1
Josh

ここで読み取りのブロックを回避することで、どのような問題を解決しようとしていますか?

移植性がないので、pollまたはselectを使用して、stdin(unixシステムでは多くの場合fd 0)で読み取るデータがあるかどうかを確認できると思います。

または、I/Oを実行する2番目のスレッドを作成し、それをブロックして、メインスレッドで通常の処理を続行できるようにすることもできます。

0
Mark B

Nathanのpeek()の回答はデータがあるかどうかを確認しますが、std::getline()が「行」の読み取りに成功するという保証はありません。

Getlineを試して、関数呼び出し自体の結果を確認するのは少し逆ですが、常にはるかに簡単です。

_std::string line;
while( !std::getline(std::cin, line) )
{
    cout << "Enter something please" << endl;
}
_

このコードは、cinが好きなものを受け取るまで実行されます(つまり、抽出してlineに配置できます)。ここではpeek()が必要または有用であるとは思いません。

編集:問題は、cin(==標準のキーボード入力)は、入力を待機しているときにプログラムをブロックする必要があるということです。待機しないときに、他にどのように入力を取得できますか?

0
rubenvb