stringstream confusion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class ISBN
{
	public:
		class Invalid{};  // exception class
		string get_ISBN() const ;
		ISBN();  // default constructor
		ISBN( int p1, int p2, int p3, char p4 ); // construct ISBN from parts
		ISBN( string full );  // construct ISBN from string
	private:
		string full_ISBN;
		int part1;
		int part2;
		int part3;
		char part4;
		void SetFull();  // Builds the full_ISBN from the individual parts
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
ISBN::ISBN( string full )
{
	stringstream tmpStream;
	string sTemp;
	int iTemp = 0;
	char cTemp = ' ';

	// extract the parts
	tmpStream.str( "" );
	sTemp = full.substr( 0, 2 );
	tmpStream << sTemp;
	tmpStream >> iTemp;
	if( iTemp < 0 || iTemp > 99 )
		throw Invalid{};
	else
		part1 = iTemp;

	tmpStream.str( "" );
	sTemp = full.substr( 3, 4 );
	tmpStream << sTemp;
	tmpStream >> iTemp;
	if( iTemp < 0 || iTemp > 9999 )
		throw Invalid{};
	else
		part2 = iTemp;

	tmpStream.str( "" );
	sTemp = full.substr( 8, 3 );
	tmpStream << sTemp;
	tmpStream >> iTemp;
	if( iTemp < 0 || iTemp > 999 )
		throw Invalid{};
	else
		part3 = iTemp;

	tmpStream.str( "" );
	sTemp = full.substr( 12, 1 );
	tmpStream << sTemp;
	tmpStream >> cTemp;
	if( (cTemp < '0' || cTemp > '9') && cTemp != 'X' )
		throw Invalid{};
	else
		part4 = cTemp;

	SetFull();
}


This constructor is supposed to take a string containing an ISBN and break out the individual parts and store them into separate integral and character members.

I run it with an example string of "01-0002-003-X" and it works great for the first part. after that, the tmpStream >> iTemp; line always sets iTemp to 1, and causes a run-time error for the cTemp extraction. What am I missing?

*edit* I've stepped through in a debugger and I know that my substringing is grabbing the proper parts from the main string.
Last edited on
Honestly, using stringstrams like that is too excessive. Simple stoi(some_substring) would suffice. Using stream to get a char you already got in a string is... not fine.

line always sets iTemp to 1, and causes a run-time error for the cTemp extraction
Line 20 sets stream in failed state and you never clear it causing all following reads to fail.

Simplified your code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ISBN::ISBN( std::string full )
{
    std::stringstream tmpStream(full);

    (tmpStream >> part1).get(); //get() is here to skip '-'
    (tmpStream >> part2).get();
    (tmpStream >> part3).get();
    (tmpStream >> part4);
    if(!tmpStream)
        std::cout << "reading failed"; //Replace with throw
    //Do parts checking, throwing etc...
    //You do not really need temporary variables for it, 
    //as you can operate on members directly without repercussions in constructor

    SetFull();
}
Last edited on
Thanks a bunch. I figured there was a better method than screwing around with all the back and forth stream business, but that's what all the examples I found were using so...
Topic archived. No new replies allowed.