std::getline on std::cin
Most likely you are trying to read a string after reading some other data, say an int
.
consider the input:
11
is a prime
if you use the following code:
std::cin>>number;
std::getline(std::cin,input)
the getline
will only read the newline after 11 and hence you will get the impression that it's not waiting for user input.
The way to resolve this is to use a dummy getline
to consume the new line after the number.
std::cin.getline( ) vs. std::cin
In case with char*, std::cin.getline
getting line, instead of std::cin
getting first word.
Why do cin and getline exhibit different reading behavior?
reading behavior of cin and getline.
cin
does not "read" anything. cin
is an input stream. cin
is getting read from. getline
reads from an input stream. The formatted extraction operator, >>
, reads from an input stream. What's doing the reading is >>
and std::getline
. std::cin
does no reading of its own. It's what's being read from.
first cin read up until the "\n". once it hit that "\n", it increments the
cursor to the next position
No it doesn't. The first >>
operator reads up until the \n
, but does not read it. \n
remains unread.
The second >>
operator starts reading with the newline character. The >>
operator skips all whitespace in the input stream before it extracts the expected value.
The detail that you're missing is that >>
skips whitespace (if there is any) before it extracts the value from the input stream, and not after.
Now, it is certainly possible that >>
finds no whitespace in the input stream before extracting the formatted value. If >>
is tasked with extracting an int
, and the input stream has just been opened and it's at the beginning of the file, and the first character in the file is a 1
, well, the >>
just doesn't skip any whitespace at all.
Finally, std::getline
does not skip any whitespace, it just reads from the input stream until it reads a \n
(or reaching the end of the input stream).
Stuck in loop during std::getline and std::cin during while loop
cin controls input from a stream buffer, which put your input characters in a stream buffer, then it was passed to getline
.cin
ends input when you signaled EOF
with Ctrl+D
, Ctrl+Z
, or Enter
.
See this link
detecting end of input with cin.
getline extracts characters from input and appends them to str until it meet one of the end conditions,
in your situaton the end condition is the endline character '\n'
, because the default delimeter is the endline character.
You may define your own delimeter getline(intput, str, $your_delemeter)
, and do a little experiment.
How to break std::cin(std::cin.getline) executuion from other thread
std::cin is a blocking call that can not be interrupted.
This thread here seems to have some non-blocking alternatives:
https://stackoverflow.com/a/40812107/2562287
If you used a non blocking alternative for std::cin along with an boolean (threadsafe from either a mutex or being atomic, preferably the latter), you could set the boolean on the other thread and read the boolean on the input thread, if the boolean is either true or false then exit the input function.
Ways std::getline(std::cin, string) can fail from keyboard input
std::getline
could fail if you've used stdin
previously without clearing the failbit and if the input exceeds std::string::max_size
(see comment of Davis Herring).
Otherwise, I know of no way to let std::getline
fail except by EOF (^Z/^D
).
But, here is your code with some small improvements:
template<typename T>
T get_type(std::string prompt)
{
T output;
std::string input;
while(true)
{
std::cout << prompt;
std::getline(std::cin, input);
std::istringstream iss(input);
if(!std::cin)
{
std::cin.clear();
// std::clearerr(stdin);
}
else if(iss >> output && iss.eof())
return output;
std::cout << "Invalid input type. Please try again:\n";
}
}
As mentioned in the comments, it is necessary to use clearerr
on stdin
on some systems. If your system requires that, just uncomment std::clearerr(stdin);
.
Because of your 2x <Enter>
problem: the ignore statement is unnecessary. You just ignore the next input (that's why you have to hit <Enter>
twice).
It seems to me as if std::getline doesn't handle new lines correctly?
std::getline()
erases the output std::string
before attempting to read from the stream.
In your second case, the first 2 calls to std::getline()
have already read everything you have typed in, there is nothing left when you press CTRL-D during the 3rd call, so there is nothing for std::getline()
to output into the std::string
.
Save the last successful line read to a separate variable, eg:
std::string user_text, line;
while(std::getline(std::cin, line))
{
user_text = line;
}
std::cout << "Text: " << user_text << std::endl;
Related Topics
Somehow Register My Classes in a List
Arithmetic Right Shift Gives Bogus Result
Call Destructor and Then Constructor (Resetting an Object)
Get Current Username in C++ on Windows
"Undefined Symbols" Linker Error with Simple Template Class
How to Get the Executable Name of a Window
C++ Comparison of Two Double Values Not Working Properly
Does (W)Ifstream Support Different Encodings
Catching "Stack Overflow" Exceptions in Recursive C++ Functions
How to Securely Disconnect an Asio Ssl Socket
How to Get the Mouse Position in a Console Program
Does Case-Switch Work Like This
Issue with Cin When Spaces Are Inputted, Using String Class
Lifetime of Lambda Objects in Relation to Function Pointer Conversion
Derived Class with Non-Virtual Destructor
Wrapping C++ Class API for C Consumption
Is There Any Reason to Use C Instead of C++ for Embedded Development