Thread: clearing wcin buffer

  1. #1
    Registered User
    Join Date
    Aug 2007
    Posts
    40

    clearing wcin buffer

    I have a function which asks for a number and keeps reasking until a real number is given, and then returns that number. It works perfectly with cin, but it doesn't when I convert everything to the wide version.

    Working version:
    Code:
    int GetCinIntInput(const string& AskText, const string& ErrorText) const
    {
    	bool ErrorDisplay = false;
    	int Input;
    	do
    	{
    		if (ErrorDisplay) cout << ErrorText << endl; //if error should be displayed display it
    		ErrorDisplay = true; //first time in the loop it's not an error, but from this point it will always be an error until the loop ends
    		cin.clear();//reset errorflags
    		cin.ignore(cin.rdbuf()->in_avail()); //ignore everything that's in the buffer
    		cout << AskText << ": "; //ask the user for the input (textwise)
    
    	}while(!(cin >> Input)); //await input and look if it goes into the integer, if it does, the loop exits and mission accomplished
    	return Input;
    }
    Not working version: cin becomes wcin, cout becomes wcout and string becomes wstring.
    It compiles but it just turns into an infinite loop of the error msg (if input is a text, it works if the input is a number).
    Last edited by s-men; 02-23-2009 at 10:33 AM.

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Let's see the code that doesn't work. Forgetting to change "cin.clear()" to "wcin" would do that.

    gg

  3. #3
    Registered User
    Join Date
    Aug 2007
    Posts
    40
    copy paste:
    Code:
    bool ErrorDisplay = false;
    	int Input;
    	do
    	{
    		if (ErrorDisplay) wcout << ErrorText << endl; //if error should be displayed display it
    		ErrorDisplay = true; //first time in the loop it's not an error, but from this point it will always be an error until the loop ends
    		wcin.clear();//reset errorflags
    		wcin.ignore(wcin.rdbuf()->in_avail()); //ignore everything that's in the buffer
    		wcout << AskText << L": "; //ask the user for the input (textwise)
    
    	}while(!(wcin >> Input)); //await input and look if it goes into the integer, if it does, the loop exits and mission accomplished
    	return Input;
    it seems
    Code:
    wcin.rdbuf()->in_avail()
    always returns 0, while it should be returning the number of characters in the buffer that are ready to be read.

    I have constructed something else in the mean time, which does the same but works:
    Code:
    int ServerEngine::GetCinIntInput(const tstring& AskText, const tstring& ErrorText) const
    {
    	bool ErrorDisplay = false;
    	int Input;
    	tstringstream tmp;
    	do
    	{
    		if (ErrorDisplay) tcout << ErrorText << endl; //if error should be displayed display it
    		ErrorDisplay = true; //first time in the loop it's not an error, but from this point it will always be an error until the loop ends
    		tcout << AskText << _T(": "); //ask the user for the input (textwise)
    		TCHAR buf[1024];
    		tcin.getline(buf,1024);
    		tmp.clear();
    		tmp.str(_T(""));
    		tmp << buf;
    
    	}while(!(tmp >> Input)); //await input and look if it goes into the integer, if it does, the loop exits and mission accomplished
    	return Input;
    }
    This is using some defines to switch between mbcs and unicode based on project settings.

    However if somebody finds out why that other method didn't work, I'm always happy to hear it and learn something new.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I would write:
    Code:
    wcin.ignore(numeric_limits<streamsize>::max());
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Aug 2007
    Posts
    40
    Quote Originally Posted by laserlight View Post
    I would write:
    Code:
    wcin.ignore(numeric_limits<streamsize>::max());
    It seems to be if you give a number of characters to ignore which is larger than the amount that is in, it will wait before continueing the code until the buffer has reached that size, if I were to pass on 10 for example, in runtime I would have to type "lol" 3 times each followed by a enter before it notifies me that an error took place because I didn't enter a valid number. And if I pass to few, e.g. 1, and I type "lol" followed by enter, it'll say the error msg 3 times.
    I haven't studied it more, but that's what my testruns showed me.
    I have also tried using an additional delimiter as second param: '\n' but on the very first execution it completely ignores the first input.
    Last edited by s-men; 02-23-2009 at 11:24 AM.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by s-men
    It seems to be if you give a number of characters to ignore which is larger than the amount that is in, it will wait before continueing the code until the buffer has reached that size
    Oh yes, I forgot that the default second argument is EOF, not '\n'.

    Quote Originally Posted by s-men
    I have also tried using an additional delimiter as second param: '\n' but on the very first execution it completely ignores the first input.
    A more canonical implementation would be:
    Code:
    int ServerEngine::GetCinIntInput(const tstring& AskText, const tstring& ErrorText) const
    {
        int Input;
        for (;;)
        {
            tcout << AskText << _T(": "); //ask the user for the input (textwise)
            if (wcin >> Input)
            {
                break;
            }
            else
            {
                tcout << ErrorText << endl;
                wcin.clear();
                wcin.ignore(numeric_limits<streamsize>::max(), '\n');
            }
        }
        return Input;
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Aug 2007
    Posts
    40
    that's working perfectly as it should too, thanks.

    Still wondering why the wide version rdbuf/in_avail behaves so differently, it may be a mystery forever

  8. #8

  9. #9
    Registered User
    Join Date
    Aug 2007
    Posts
    40
    Quote Originally Posted by Codeplug View Post
    Which STL are you using?

    gg
    Not sure if I know what you mean, but I'm using the headers supplied by Visual Studio 2005.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Proper method of clearing buffer
    By Oldman47 in forum C++ Programming
    Replies: 14
    Last Post: 04-23-2007, 07:14 PM
  2. Replies: 16
    Last Post: 10-29-2006, 05:04 AM
  3. Clearing input buffer after using getch()
    By milkydoo in forum C++ Programming
    Replies: 3
    Last Post: 07-21-2003, 11:04 PM
  4. text input buffer clearing
    By red_Marvin in forum C++ Programming
    Replies: 4
    Last Post: 03-20-2003, 03:17 PM
  5. Console Screen Buffer
    By GaPe in forum Windows Programming
    Replies: 0
    Last Post: 02-06-2003, 05:15 AM