Namespaces
Variants
Views
Actions

Talk:cpp/string/basic string/getline

From cppreference.com

ImproperSubset (talk) 06:45, 4 October 2018 (PDT): The example code leaves the stream with the fail bit set. If I had the exception mask set to include the fail bit, it would throw. Is this intentional for some reason I have simply missed? I think a better exit state for the loop would be for eof to be set and fail to be clear.

it's just how getline is specified to work. As this page puts it, "If no characters were extracted for whatever reason, getline sets failbit and returns." --Cubbi (talk) 07:55, 4 October 2018 (PDT)

I understand that the behavior is correct. My understanding is indeed owed to the superb explanation on the page. I'm just suggesting that an example of how to use std::getline that results in less surprising behavior might be an improvement. When I adapted the example for my purposes, I settled on a control structure that looked like this:

   std::string line;
   while ( !(input >> std::ws).eof() ) {
       std::getline(input, line);
       sum += std::stoi(line);
   }
   std::cout << "eof: " << input.eof() << " fail: " << input.fail() << std::endl;

This exits the loop with eof set and fail not set:

 What is your name? Hello , nice to meet you.
 eof: 1 fail: 0
 
 The sum is: 28

ImproperSubset (talk) 11:48, 4 October 2018 (PDT)

The example is currently showing an idiomatic C++ input loop, that is, how this function is designed to be used. Other input loops (with various operator>> overloads, with get, etc) also leave their input streams in eof+fail. That's just how things are, pure eof bit is rare and short-lived (start of any input operation converts it to fail+eof before doing anything). I suppose it deserves a small note on cpp/io/ios_base/iostate --Cubbi (talk) 12:04, 4 October 2018 (PDT)

[edit] Getline with lineending

Below: If the last line does not end with newline, don't put it in!

#include <iostream>
#include <sstream>
std::istream &getline_with_lineending(std::istream &is, std::string &s)
{
    if (std::getline(is, s) && !is.eof()) {
        s += is.widen('\n');
    }
    return is;
}
 
int main()
{
    std::istringstream iss{"a\nb\nc"};
    for (std::string s; getline_with_lineending(iss, s); ) {
        std::cout << s;
    }
}