| | |
Input Stream Questions
Please support our C++ advertiser: Intel Parallel Studio Home
Thread Solved |
•
•
Join Date: Feb 2008
Posts: 67
Reputation:
Solved Threads: 1
I have a feeling ya'll get plenty of cin questions here and are quit tired of them, but I have a few that are a little more in depth. I started trying to write my own input stream flush template and had some very minor successes when I found the sticky at the top of this and found a break through. Here is what I wrote after the breakthrough I played around with the solution the sticky offered and got to this, but it doesn't work in my codes.
Question 1) What exactly does widen() do? I've seen it several times but don't really understand what it is accomplishing.
Question 2) Why does the first one work perfectly but the second one not fix the input stream?
c++ Syntax (Toggle Plain Text)
template <typename CharT> void flush(std::basic_istream<CharT> &in) { in.clear(); char nextChar= in.get(); while(nextChar != '\n' && nextChar != std::char_traits<CharT>::eof()) nextChar= in.get(); in.clear(); } template <typename CharT, typename var_type> void extractr(std::basic_istream<CharT> &in, var_type &var, bool FLUSH= false) { if(!in) flush(in); in >> var; while(!in) { cout << "\nInvalid data type, please enter a " << typeid(var).name() << endl << "-> "; flush(in); in >> var; } if(FLUSH) flush(in); }
c++ Syntax (Toggle Plain Text)
template <typename CharT> void ignore_line(std::basic_istream<CharT> &in) { in.clear(); if(in.rdbuf()->sungetc() != std::char_traits<CharT>::eof() && in.get() != '\n') in.ignore(std::numeric_limits<std::streamsize>::max(), in.widen('\n')); in.clear(); }
Question 1) What exactly does widen() do? I've seen it several times but don't really understand what it is accomplishing.
Question 2) Why does the first one work perfectly but the second one not fix the input stream?
Last edited by c++noobie; Oct 21st, 2008 at 4:31 pm.
>Question 1) What exactly does widen() do?
It takes the character you pass and converts it to the locale the stream is imbued with. For example, you want to convert a character literal to the appropriate wchar_t value if the stream is wide oriented, but leave it as is if the stream is not wide oriented.
>Question 2) Why does the first one work perfectly
>but the second one not fix the input stream?
It's hard to say without seeing how you're testing the code, but I'd guess you're immediately entering invalid data. Because no characters have been successfully extracted, sungetc returns eof() and the ignore isn't performed. The effect is the same as if the stream were empty.
The first function works because you're extracting characters and not relying on the previously extracted character, which might not exist for this particular usage, but it basically negates the solution provided in the second function because you're back to blocking reads.
It takes the character you pass and converts it to the locale the stream is imbued with. For example, you want to convert a character literal to the appropriate wchar_t value if the stream is wide oriented, but leave it as is if the stream is not wide oriented.
>Question 2) Why does the first one work perfectly
>but the second one not fix the input stream?
It's hard to say without seeing how you're testing the code, but I'd guess you're immediately entering invalid data. Because no characters have been successfully extracted, sungetc returns eof() and the ignore isn't performed. The effect is the same as if the stream were empty.
The first function works because you're extracting characters and not relying on the previously extracted character, which might not exist for this particular usage, but it basically negates the solution provided in the second function because you're back to blocking reads.
I'm here to prove you wrong.
•
•
Join Date: Feb 2008
Posts: 67
Reputation:
Solved Threads: 1
I've played around with some inputs and such looking at it from that point of view and it makes sense. I still don't fully understand why it remains in an error state, even if the ignore() is ignored. When using flush, this will continue to ask for a corrected input until it receives one, but it will pause at the beginning of the program because it needs something for in.get(). When using ignore_line, this will ask for corrected input once after receiving incorrect int input (or using leftover from something like "asdf" for char input) but will enter an infinite loop (due to error state in cin) after any further incorrect input. Two questions again, why does it behave like that? and is there a usable and possibly portable solution?
c++ Syntax (Toggle Plain Text)
void main() { flush(cin); char c; cout << "char? "; extractr(cin, c); cout << "char: " << c << endl; int var; cout << "int? "; extractr(cin, var); cout << "int: " << var << endl; }
Last edited by c++noobie; Oct 22nd, 2008 at 2:21 am.
>I still don't fully understand why it remains in an error state, even if the ignore() is ignored.
It doesn't remain in an error state, but because the bad data isn't extracted, you immediately enter the same error state again as soon as you say
>why does it behave like that?
If the stream is empty, sungetc will return eof(). If the stream is not empty and the last extracted character is not '\n', the entire line will be ignored. Here's what happens with "asdf" as the first input and "hjkl" as the second input:
Add another level of abstraction where you can count the number of times ignore_line fails to clear the stream. If it does so more than a set number of times, which you would specify as the threshold for an infinite loop, force ignore to be called:
It doesn't remain in an error state, but because the bad data isn't extracted, you immediately enter the same error state again as soon as you say
in >> var; in extractr after trying to ignore the line.>why does it behave like that?
If the stream is empty, sungetc will return eof(). If the stream is not empty and the last extracted character is not '\n', the entire line will be ignored. Here's what happens with "asdf" as the first input and "hjkl" as the second input:
- 'a' is extracted by the first call of extractr.
- 's' causes the second call of extractr to fail (it's not an int) and because the last extracted character was 'a', the condition in ignore_line is met and ignore is called. This extracts the rest of the line and leaves the stream empty.
- extractr prompts for correct input, but the next character is 'h', which fails because it isn't an int. However, because the stream is empty, sungetc returns eof() and the ignore isn't performed. Nowhere else in the error loop of extractr do you clear out bad characters, so the loop will run infinitely by erroring on 'h'.
Add another level of abstraction where you can count the number of times ignore_line fails to clear the stream. If it does so more than a set number of times, which you would specify as the threshold for an infinite loop, force ignore to be called:
C++ Syntax (Toggle Plain Text)
template <typename CharT> bool flush ( std::basic_istream<CharT>& in, bool always_flush ) { in.clear(); if ( always_flush || in.rdbuf()->sungetc() != std::char_traits<CharT>::eof() && in.get() != '\n' ) { in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) ); return true; } in.clear(); return false; } template <typename CharT> void flush ( std::basic_istream<CharT>& in ) { int failed = 0; while ( !flush ( in, false ) ) { if ( ++failed > 1 ) { flush ( in, true ); break; } } }
I'm here to prove you wrong.
•
•
Join Date: Feb 2008
Posts: 67
Reputation:
Solved Threads: 1
First of all, thank you so much for all of this help, it's really helping me understand all of this.
Second, I did a lot more looking into it and reading, and I think I came up with something (closely related to your ignore and pause classes as I looked at those quite a bit). It works well, although, I am unsure about the parts involving _nread. If there is a better way to do this, please let me know. Also, whenever I enter "asdf" for the first input, the first ignore count comes out to be 1 when it seems to me that it should be 4 (ignoring 'sdf\n'). Again, thank you so much for all of this, I think I'm understanding all of these concepts quite a bit better now.
Second, I did a lot more looking into it and reading, and I think I came up with something (closely related to your ignore and pause classes as I looked at those quite a bit).
c++ Syntax (Toggle Plain Text)
template <typename CharT> std::streamsize ignore_line( std::basic_istream<CharT> &in, bool always_ignore= false ) { std::streamsize nread= 0; in.clear(); if( always_ignore || ( in.rdbuf()->sungetc() != std::char_traits<CharT>::eof() && in.get() != '\n' ) ) { in.ignore( std::numeric_limits<std::streamsize>::max(), in.widen('\n') ); nread= in.gcount(); } in.clear(); return nread; } template <typename var_type> class extract { var_type *var; bool _always_flush, _full_count; mutable std::streamsize *_nread; public: extract( var_type &input, bool always_flush= false ) : _always_flush(always_flush), _nread(0), var(&input), _full_count(false) {} extract( var_type &input, std::streamsize &nread, bool always_flush= false ) : _always_flush(always_flush), _nread(&nread), var(&input), _full_count(false) {*_nread=0;} //_nread[0] holds pre-extraction character ignore count //_nread[1] holds mid-extraction character ignore count //_nread[2] holds post-extraction character ignore count extract( var_type &input, std::streamsize nread[3], bool always_flush= false ) : _always_flush(always_flush), _nread(nread), var(&input), _full_count(true) {_nread[0]=0;_nread[1]=0;_nread[2]=0;} template <typename CharT> friend std::basic_istream<CharT> &operator>> ( std::basic_istream<CharT> &in, const extract &manip ) { int _ignore_count= 0; if( manip._always_flush || !in ) manip._nread[0]+=ignore_line(in); in >> *manip.var; while(!in) { cout << "\nInvalid data type, please enter a value of type: " << typeid(*manip.var).name() << "\n-> "; _ignore_count+= ignore_line(in, true); in >> *manip.var; } if(manip._full_count) { manip._nread[1]= _ignore_count; _ignore_count= 0; } if(manip._always_flush) _ignore_count+= *manip._nread= ignore_line(in); if(manip._full_count) manip._nread[2]= _ignore_count; return in; } }; void main() { int i; char c; string s; std::streamsize chars[3]; cout << "char? "; cin >> extract<char>(c); cout << "char: " << c << endl; cout << "int? "; cin >> extract<int>(i, chars, true); cout << "int: " << i << endl << "ignored: " << chars[0] << ' ' << chars[1] << ' ' << chars[2] << endl; cout << "string? "; cin >> extract<string>(s); cout << "string: " << s << endl; }
>whenever I enter "asdf" for the first input, the first ignore count comes
>out to be 1 when it seems to me that it should be 4 (ignoring 'sdf\n')
Run it through a debugger and check the values returned by ignore_line. I imagine you'll find them to be correct, and that should help you pinpoint the real problem.
>out to be 1 when it seems to me that it should be 4 (ignoring 'sdf\n')
Run it through a debugger and check the values returned by ignore_line. I imagine you'll find them to be correct, and that should help you pinpoint the real problem.
I'm here to prove you wrong.
![]() |
Similar Threads
- questions on radix sort programs (C++)
- The input stream class... (C++)
- questions with case statements (C++)
- isalpha and ASCII questions (C)
- Help with dates (C)
- program overwritng the 1st input (C++)
- Help Me Please (C++)
- reading input ... quick C++ question ... (C++)
Other Threads in the C++ Forum
- Previous Thread: need help parsing output for Asterisk Manager's Interface
- Next Thread: priority_queue help
| Thread Tools | Search this Thread |
api array arrays based beginner binary bitmap c++ c/c++ calculator char class classes code compile compiler console conversion count data delete deploy desktop developer directshow dll download dynamic encryption error file forms fstream function functions game getline givemetehcodez google graph gui homeworkhelp homeworkhelper iamthwee ifstream input int integer java lib linkedlist linker linux list loop looping loops map math matrix memory news node number output parameter pointer problem program programming project proxy python read recursion recursive return string strings struct temperature template templates test text text-file tree unix url variable vector video visual visualstudio win32 windows winsock word wordfrequency wxwidgets






