Strange problem of typecasting with stringstream

V

vigacmoe

I was trying to cast some strings to integers with stringstream, then
this strange problem poped up.
Here is my test code:

stringstream conv;
string from;
int to;

from = "1";
conv << from;
conv >> to;

from = "2";
conv << from;
conv >> to;

The first casting worked fine, but the second casting didn't work at
all.
conv.str() returned "1" after 'from = "2"; conv << from;' was executed.
Then I explicitly changed the buffer of conv, like this:

conv.str("1");
conv >> to;

conv.str("2");
conv >> to;

Still, the first casting worked perfectly, the second one failed, to ==
1.
I'm wondering I've terribly misunderstanding something, sorry if I'm
asking the obvious.
 
J

Jim Langston

I was trying to cast some strings to integers with stringstream, then
this strange problem poped up.
Here is my test code:

stringstream conv;
string from;
int to;

from = "1";
conv << from;
conv >> to;

from = "2";
conv << from;
conv >> to;

The first casting worked fine, but the second casting didn't work at
all.
conv.str() returned "1" after 'from = "2"; conv << from;' was executed.
Then I explicitly changed the buffer of conv, like this:

conv.str("1");
conv >> to;

conv.str("2");
conv >> to;

Still, the first casting worked perfectly, the second one failed, to ==
1.
I'm wondering I've terribly misunderstanding something, sorry if I'm
asking the obvious.

I"m suspecting that the stringstream is having "12" instead of "1 2" or
soemthing. I would try the following til I found what worked.

from = "1";
conv << from;
conv >> to;

from = " 2";
conv << from;
conv >> to;

if that didnt' work see what

from = "1 2";
conv << from;
conv >> to;
conv >> to;

gives you.

You may need to reset the stringstream in between, but I've never had that
problem.
 
S

Sumit Rajan

I was trying to cast some strings to integers with stringstream, then
this strange problem poped up.
Here is my test code:

stringstream conv;
string from;
int to;

from = "1";
conv << from;
conv >> to;
Try:
conv.clear();


from = "2";
conv << from;
conv >> to;

Regards,
Sumit.
 
G

Gan Quan

Jim said:
from = "1";
conv << from;
conv >> to;

from = " 2";
conv << from;
conv >> to;
didn't work.
from = " 2";
conv << from;
didn't change the inner buffer of conv, conv.str() still returned "1".
if that didnt' work see what

from = "1 2";
conv << from;
conv >> to;
conv >> to;
this worked.
 
G

Gan Quan

Sumit said:
Try:
conv.clear();
yes, conv.clear() did the job, but why the previous method doesn't
work?
I've done some test, it seems that if conv's internal pointer ever
pointed to the end of its buffer, the next << operation would fail.
These code worked as intended:
conv << "1"; /* conv.str() = "1", conv.tellg() = 0 */
conv << " 2"; /* conv.str() = "1 2", conv.tellg() = 0 */
conv >> to; /* conv.str() = "1 2", conv.tellg() = 1, to =
1*/
conv << " 3"; /* conv.str() = "1 2 3", conv.tellg() = 1 */
conv >> to; /* conv.str() = "1 2 3", conv.tellg() = 3, to =
2 */
but these didn't
conv1 << "1"; /* conv.str() = "1", conv.tellg() = 0 */
conv1 << " 2"; /* conv.str() = "1 2", conv.tellg() = 0 */
conv1 >> to; /* conv.str() = "1 2", conv.tellg() = 1, to =
1 */
conv1 >> to; /* conv.str() = "1 2", conv.tellg() = 3, to =
2, internal pointer reached the end */
conv1 << " 3"; /* conv.str() = "1 2", conv.tellg() = -1, <<
operation failed */
conv1 >> to; /* conv.str() = "1 2", conv.tellg() = -1, to =
2 */
I did the test on MS Visual Studio .NET 2003, is this a bug of the
standard library implementation I'm using?
 
F

F.J.K.

I was trying to cast some strings to integers with stringstream, then
this strange problem poped up.
Here is my test code:

Doesn't compile. Please post complete programs, see
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8
stringstream conv;
string from;
int to;

from = "1";
conv << from;
conv >> to;

So what do you think happens in the last line. To be like the library,
you have to think like the library :) You read all characters upto and
including EOF. Thus setting state |= eofbit in conv. Thus making the
stream invalid for all further operations.
from = "2";
conv << from;
conv >> to;

The << operator returns without doing anything, because your eofbit is
set. The >> operator returns without doing anything, because the eofbit
is set.
conv.str() returned "1" after 'from = "2"; conv << from;' was executed.

Well, conv << from; was a NOP for the reasons mentioned. conv.str() is
"1" before you do nothing. It will still return "1" after you do
nothing.
Then I explicitly changed the buffer of conv, like this:

conv.str("1");
conv >> to;

conv.str("2");
conv >> to;

Still, the first casting worked perfectly, the second one failed, to ==
1.

There is no casting in your code. You probably have a scripting
language background, like perl. The terms we use in C++ for read
operations is something like "the first read". Casting is a different
concept and quite a subject in itself. Btw, if you take care not to
read EOF by adding a whitespace like " " or "\n", everything works
fine.

#include <sstream>
#include <iostream>

int main () {
std::stringstream conv("1\n");
int to;
conv >> to;
std::cout << to << "\n";
conv.str("2\n");
conv >> to;
std::cout << to << "\n";
}
I'm wondering I've terribly misunderstanding something, sorry if I'm
asking the obvious.

Your doing fine. You are just a little bit careless. And you should use
an IDE with a debugger. If you singlestep your program, the state
member of your stringstream will instantly tell you what's happend.
 
B

BobR

Gan Quan wrote in message
yes, conv.clear() did the job, but why the previous method doesn't
work?
I've done some test, it seems that if conv's internal pointer ever
pointed to the end of its buffer, the next << operation would fail.
These code worked as intended:
conv << "1"; /* conv.str() = "1", conv.tellg() = 0 */
conv << " 2"; /* conv.str() = "1 2", conv.tellg() = 0 */
conv >> to; /* conv.str() = "1 2", conv.tellg() = 1, to =
1*/
conv << " 3"; /* conv.str() = "1 2 3", conv.tellg() = 1 */
conv >> to; /* conv.str() = "1 2 3", conv.tellg() = 3, to =
2 */
but these didn't
conv1 << "1"; /* conv.str() = "1", conv.tellg() = 0 */
conv1 << " 2"; /* conv.str() = "1 2", conv.tellg() = 0 */
conv1 >> to; /* conv.str() = "1 2", conv.tellg() = 1, to =
1 */
conv1 >> to; /* conv.str() = "1 2", conv.tellg() = 3, to =
2, internal pointer reached the end */
conv1 << " 3"; /* conv.str() = "1 2", conv.tellg() = -1, <<
operation failed */
conv1 >> to; /* conv.str() = "1 2", conv.tellg() = -1, to =
2 */
I did the test on MS Visual Studio .NET 2003, is this a bug of the
standard library implementation I'm using?

No, I don't think so. See my example below.

std::stringstream conv;
std::string from;
int to;

from = "1";
conv << from;
conv >> to;
std::cout<<conv.str()<<" to="<<to<<std::endl;

// stringstream is now in a 'failed' state.... (sort of<G>)

from = "2";
conv << from;
conv >> to;
std::cout<<conv.str()<<" to="<<to<<std::endl;

// ...so, trying to set it to "2" fails.

conv.clear(); // reset the stream to a 'good' state
from = "2";
conv << from;
conv >> to;
std::cout<<conv.str()<<" to="<<to<<std::endl;

// see below

conv.str(""); // 'clear' the buffer
conv.clear(); // and 'reset' it.
from = "2";
conv << from;
conv >> to;
std::cout<<conv.str()<<" to="<<to<<std::endl;
/* -- output --
1 to=1
1 to=1
12 to=2 // using only '.clear()'
2 to=2
*/
 
B

BobR

BTW, if you do a whole bunch of string-to-number/number-to-string converting,
you may want these templates (put them in header file):
[ these were in a FAQ, but, I couldn't remember which one[1], so, I post
it.<G>]

#include <iostream>
// ------- any number to string, string to any number -------
#include <string>
#include<sstream>
#include <iomanip> // for 'setprecision()'
template<typename T> T FromString( std::string const &s){
std::istringstream is( s ); T t; is >> t; return t;
} // FromString(string&)
template<typename T> std::string ToString( T const &t, size_t prec = 6){
// std::eek:stringstream s; s << t; return s.str(); // original
std::eek:stringstream s;
s.setf(std::ios_base::fixed);
s <<std::setprecision( prec )<< t;
return s.str();
} // ToString(T&,size_t)
// ------------------------------------------------------

void TestPrint(){
using std::cout;
double Dnum(12345.6789);
std::string txt = ToString( Dnum );
double Dnum2 = FromString<double>( txt );
cout<<" ------- "<<std::endl;
cout<<" Dnum="<<Dnum<<std::endl;
cout<<" txt="<<txt<<std::endl;
cout<<" Dnum2="<<Dnum2<<std::endl;
cout<<" ------- "<<std::endl;
int Dnum3(12345);
txt = ToString( Dnum3 );
int Dnum4 = FromString<int>( txt );
cout<<" Dnum3="<<Dnum3<<std::endl;
cout<<" txt="<<txt<<std::endl;
cout<<" Dnum4="<<Dnum4<<std::endl;
cout<<" ------- "<<std::endl;
return;
} // TestPrint()

int main(){
TestPrint();
return 0;
} // main()


[1] - CRS and Sometimers!
 
B

BobR

Thomas J. Gritzan wrote in message ...
BobR said:
BTW, if you do a whole bunch of string-to-number/number-to-string converting,
you may want these templates (put them in header file):
[ these were in a FAQ, but, I couldn't remember which one[1], so, I post
it.<G>]
[snipped code]

It's not the same code you posted, but it handles bad conversion:

From 39.1 to 39.3:
http://www.parashift.com/c++-faq-lite/misc-technical-issues.html

Guess what? I clicked your link while off-line and up-it-poped! That was what
I was looking for, thanks. [d a r n CRS!!]

Now I only have to do a search for what dang partition/folder I put it in!
[..and move it to the proper place - in my library.]
 
G

Gan Quan

F.J.K. 写é“:
Doesn't compile. Please post complete programs, see
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8


So what do you think happens in the last line. To be like the library,
you have to think like the library :) You read all characters upto and
including EOF. Thus setting state |= eofbit in conv. Thus making the
stream invalid for all further operations.
Thanks, this explains everything, I didn't notice the state change,
though I did notice that once the internal pointer reach the end of the
buffer, the next read/write operation would fail ;)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top