Reputation: 587
I have two pieces of code.They work properly when it is used alone in the main()
.
vector<int> v;
cout << "Enter sequance of integers "<< "(press q to quit) : ";
istream_iterator<int> start_cin(cin);
istream_iterator<int> end_of_cin;
copy(start_cin,end_of_cin,back_inserter(v));
for ( vector<int>::iterator It = v.begin();It != v.end(); It++ )
cout << *It << "\t";
cout << endl;
and
vector<string> vS;
cout << "Enter three strings : ";
for ( int i = 0; i < 3; i++ )
vS.push_back(*istream_iterator<string>(cin));
ostream_iterator<string> sIt(cout,", ");
copy(vS.begin(),vS.end(),sIt);
cout << endl;
When these two part use together,i.e
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
using namespace std;
int main ()
{
// first part
vector<int> v;
cout << "Enter sequance of integers "<< "(press q to quit) : ";
istream_iterator<int> start_cin(cin);
istream_iterator<int> end_of_cin;
copy(start_cin,end_of_cin,back_inserter(v));
for ( vector<int>::iterator It = v.begin();It != v.end(); It++ )
cout << *It << " \t";
cout << endl;
vector<string> vS;
cout << "Enter three strings : ";
for ( int i = 0; i < 3; i++ )
vS.push_back(*istream_iterator<string>(cin));
ostream_iterator<string> sIt(cout,", ");
copy(vS.begin(),vS.end(),sIt);
cout << endl;
return 0;
}
here first part worked but second part give output: Enter Three Strings : , , ,
.
I want to know that what is the reason behind this behaviour?
Thanks.
Upvotes: 0
Views: 1190
Reputation: 122001
After the copy()
has completed cin
will be in an unreadable state (!cin.good()
), due to the failed read of the "integer" q
. This means the subsequent for
loop will fail to read anything.
Add:
cin.clear();
cin.ignore(); // To skip the unread "q"
before the for
loop.
EDIT:
As commented by James Kanze, check to ensure "q"
was the cause of the termination of the copy()
:
...
cin.clear();
string int_read_terminator;
cin >> int_read_terminator;
if ("q" != int_read_terminator)
{
cerr << "Integer copy() failure: " << int_read_terminator << "\n";
}
else
{
...
Upvotes: 3
Reputation: 154027
You've just encountered one of the problems with input_iterator
: it
requires the entire file to be of one type. There are several ways of
working around this; the most general is to insert a filtering streambuf
between the actual source and the stream. Thus, for example, the first
part of your stream should terminate when you enter a single line with
just a 'q'
, something like:
class UntilQStreambuf : public std::streambuf
{
std::streambuf* mySource;
char myBuffer;
bool myIsAtStartOfLine;
protected:
int underflow()
{
int results = mySource->sbumpc();
if ( results == 'q'
&& myIsAtStartOfLine
&& mySource->sgetc() == '\n' ) {
mySource->sbumpc(); // remove terminator line.
results = traits_type::eof();
}
if ( results != traits_type::eof() ) {
myBuffer = results;
setg( &myBuffer, &myBuffer, &myBuffer + 1 );
}
return results;
}
public:
UntilQStreambuf( std::istream& source )
: mySource( source->rdbuf() )
, myIsAtStartOfLine( true )
{
}
};
(I think boost::iostream
has some support which would make this
significantly simpler to write.) You then set up a separate stream for
reading the numbers, using the streambuf
from std::cin
(or
whereever):
std::vector<int>
getNumbers( std::istream& source )
{
UntilQStreambuf localSB( source );
std::istream src( &localSB );
std::vector<int> results( (std::istream_iterator<int>( src )),
(std::istream_iterator<int>()) );
if ( !src.eof() ) {
// Some other error occurred...
}
return results;
}
By using a separate stream, the end condition won't be set in the original stream, and you can continue with it later (perhaps using more of the same technique).
Upvotes: 0