Noob stringstream problem

Started by
3 comments, last by Robione 14 years, 10 months ago
I haven't used streams much at all. I was curious as to why the line "ss << fixed << d << endl;" puts nothing into the stream (seen in the debugger in the data member ss._Sb._Seekhigh). Variables are: str = CString (MFC) ss = stringstream d = double dprec = double representing minimum price movement dig = byte representing number of digits in deicmal fraction. Globals are there just to get the behavior of the control working correctly for the moment. This function is part of a subclassed single line CEdit control. The problem I'm trying to fix is that I only want x digits displayed in the control. Let's say I start at 1.0001 and dprec = 0.0001.... everything is great until 1.0004. That's when the next up-arrow results in 1.000499999 and when I only use "dec_ = str.Mid(dec,::dig);" that's a just a substring so I'm "stuck" on 1.0004. Using streams properly rounds up the last significant figure..... except nothing is going back into the stream after the 1st two operations :/ Thanks
void CPriceEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default

	if(nChar == VK_UP || nChar == VK_DOWN) {
		GetWindowText(str);

		ss << str.GetBuffer(0);
		ss >> d;

//		d = ::strtod(str.GetBuffer(0),NULL);

		if(nChar == VK_UP) d += (::dprec * nRepCnt);
		else d -= (::dprec * nRepCnt);

		ss.precision(::dig);
		ss << fixed << d << endl;
		str = ss.str().c_str();

/*		str = ::_ecvt(d,20,&dec,&sign);
		int_ = str.Left(dec);
		dec_ = str.Mid(dec,::dig);
		str.Format("%s.%s",int_,dec_);
*/
		this->SetWindowText(str);
		return;
	}

	CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
}

Advertisement
From this code it looks like the stringstream is a member / global. The problem may well be that stringstream (like other streams) can get invalidated easily and go into an error state, not accepting input/output any more. You could see what if (ss) or ss.good() says.

The usual "workaround" to these problems is to use streams as local variables and start with a fresh new one each time. Otherwise you might try if ignore() and clear() members help.

---------
Eventually you could also just use scanf to format a double, or if you want it typesafe there's Boost.Format.
Thanks. As soon as you mentioned the flags I thought of the eof bit.... and sure enough that's the cause. The clear() function sort of works. I can read in the value. The problem then became the stringbuf object still had the previous value in it.... so it looked like the two (or more) values were concatenated.

I then used seekp() which worked... for one press of the up arrow. Then failed for the rest. Seems like streams are "easy to use" when they don't stick around for a while LOL.

	ss.seekp(ios_base::beg).clear();	ss.precision(::dig);	ss << fixed << d;


Only reason I wanted to keep the stringstream object around was because the user more than likely could press and hold the arrow key, which would be a lot of stuff going on in the stack and heap (maybe it's not as bad as I think :? ). So ss, str and d are protected members of CPriceEdit and will exist as long as the dialog box is open instead of for each call of OnKeyDown().

Now with the seekp() call a locally declared stringstream works properly.... any idea how I might get it to work as a class member?

I need to look for a book on boost.... seems like everyone is using it. Never heard of it 'til a week or so ago.
I suppose the ignore member should be able to clear the existing contents of a stringstream too.

Another thing is that if you didn't "extract" the contents with the str() member but used getline or >>, then that should remove read contents from the stream.

But I doubt there is much reason to worry about efficiency in something that deals with tiny amounts of memory and is called very-very seldom (speed of user input is slow compared to what the computer could do if not for the user).
Well I tried a bunch of things and got it working. TYVM for the help.

I had to call "ss.str("");" prior to reading in the CString with GetBuffer(). I was looking at the debugger..... apparently ss.str() returns the pointer either _GBeg or _PBeg (and not _GNext or_PNext). These two pointers (_Beg) for whatever reason retain the values after any <<, >>, ignore(), getline() calls. So after several presses of the up arrow _PBeg/_GBeg have the following value: 1.00021.00031.0004 while the next pointers are both empty.

Who knew str() work off _Beg and <</>> work off _Next. LOL

	switch(nChar) {	case VK_UP:	case VK_DOWN:		GetWindowText(str);				ss.str("");		ss << str.GetBuffer(0);		ss >> d;		if(nChar == VK_UP) d += (::dprec * nRepCnt);		else d -= (::dprec * nRepCnt);		ss.seekp(ios_base::beg).clear();		ss.precision(::dig);		ss << fixed << d;		str = ss.str().c_str();		this->SetWindowText(str);		this->SetSel(byPos,byPos);		return;	case VK_LEFT:		if(byPos) --byPos;		break;	case VK_RIGHT:		if(byPos < ::ilim) ++byPos;	}

This topic is closed to new replies.

Advertisement