Sign in to follow this  

Noob stringstream problem

This topic is 3099 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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);
}

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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;
}


Share this post


Link to post
Share on other sites

This topic is 3099 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this