-
[C++] stringstream을 while문의 조건으로 사용할 때 주의할 점Study/C & C++ 2022. 10. 13. 14:13
코딩 테스트 문제를 풀다 보면 stringstream으로 값을 추출할 때가 많다.
공백이나 특정 문자 기준으로 잘라내기 위해 while문과 stringstream 객체를 조합하여 사용할 경우가 많다.
stringstream객체를 while문의 조건으로 사용할 때, 주의하지 않으면 분명 다 읽었는데 반복을 한 번 더 돌거나 하는 문제가 생길 수 있다.
아래 코드는 공백으로 구분된 문자열을 받아, 공백을 지우고 출력하는 코드이다.
#include <iostream> #include <string> #include <sstream> using namespace std; int main() { string input; getline(cin, input); // 개행문자 전까지 한 줄 읽음 stringstream ss(input); string buf; while (ss) { // 공백 단위로 잘라서 출력 ss >> buf; cout << buf; } return 0; }
출력 결과는 다음과 같았다.
Anger가 두 번 출력되는 현상을 볼 수 있다.
이는 마지막 Anger라는 문자를 읽고, buf가 초기화가 되지 않은 상태로 한 번 더 반복했다는 뜻이다.
현재 while문의 조건으로 stringstream객체 자체를 넣어주고 있는데, 이 조건이 문제라고 할 수 있다.
while문의 조건으로 stringstream이 들어가면, stringstream은 오버로딩된 bool()연산자에 의해 bool type으로 형변환된다.
stringstream은 iostate flag에 따라 bool type 형변환 결과가 다르다.
문서를 보자.
출처 : https://en.cppreference.com/w/cpp/io/basic_ios/operator_bool 여기서 주목할 부분은, eof()가 true일 때의 bool 형변환 결과이다.
eof()가 true일 때도, bool type 형변환 결과가 true인 것을 볼 수 있다.
위 코드에서 마지막 anger문자열을 읽으면, stringstream의 eof flag는 true가 된다.
그리고 다시 while의 조건문으로 돌아가며, stringstream객체는 flag 상태에 의해 true를 반환하기에 한 번 더 반복하게 된다.
그리고 한 번 더 >> 연산자로 추출을 시도하면 fail bit가 true로 전환, while문의 조건을 만족하지 못해 그제야 반복이 끝나게 되는 것이다.
확인을 위해 반복할때마다 flag 상태를 출력해보겠다.
#include <iostream> #include <string> #include <sstream> using namespace std; int main() { string input; getline(cin, input); // 개행문자 전까지 한 줄 읽음 stringstream ss(input); string buf; while (ss) { // 공백 단위로 잘라서 출력 ss >> buf; cout << buf << '\n'; cout << "eof : " << std::boolalpha << ss.eof() << '\t'; cout << "fail : " << std::boolalpha << ss.fail() << '\n'; cout << "=======================================\n"; } return 0; }
Anger를 읽을 때의 flag상태를 보자 Anger를 처음 읽은 후, eof가 true상태가 되고, 한 번 더 읽은 후에야 fail이 true로 전환되는 모습을 볼 수 있다.
결론
while (ss >> buf) { // 공백 단위로 잘라서 출력 cout << buf << '\n'; }
이런 식으로 ss >> buf 를 조건문 자체에 넣으면, >> operator의 반환값으로 istream&이 반환된다.
이 istream&은 >> 연산이 실행된 이후이므로, failbit가 켜지자마자 조건을 충족하지 않아 반복을 끝내게 된다.
참고로, 절대 while문 조건에 ss.eof()를 넣으면 안 된다.
eof()는 읽기가 안전하다는 것을 보장하지 않기 때문이다.
읽기 도중 알 수 없는 이유로 badbit나 failbit가 켜지는 경우를 생각해보면 된다.
https://stackoverflow.com/questions/20572203/detect-when-at-the-end-of-a-stringstream
Detect when at the end of a stringstream
I am trying to write a function which will detect when I'm almost at the end of a stringstream, but it doesn't seem to work. Here's some code: std::string path(1.2.3); int number; std::stringstr...
stackoverflow.com
https://stackoverflow.com/questions/47876920/stringstream-c-while-loop
Stringstream c++ while loop
Program finds integeres between commas like "2,33,5" -> 2 33 5. The problem is why is it working if I put for example string like "0,12,4". shouldn't the stringstream put 0 into tmp so the loop was...
stackoverflow.com
씹어먹는 C++ - <7 - 2. C++ 에서 파일 입출력 - std::ifstream. std::ofstream, std::stringstream>
modoocode.com
'Study > C & C++' 카테고리의 다른 글
[C++] 복사 생성자와 RVO, NRVO (1) 2022.09.19 [따배씨++] 변수, 상수, 전처리기 등 정리 (0) 2022.09.16 [C] 버퍼(stdin)에 대한 이해와 scanf의 문제점 (0) 2022.09.14