Re: The behavior of istream.
On 02/28/14, somenath wrote:
I was trying to understand the concept of Iterator from the book "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
I was trying to understand the program in Chapter 20.6.2
But the exact copy of the code was crashing and was not able to read the newline also from the console.
So I did little bit of experiment and change the code as follows
#include <iostream>
#include<list>
#include <vector>
using namespace std;
class Text_iterator;
typedef vector<char> Line;
class Text_iterator {
list<Line>::iterator ln;
Line::iterator pos;
public:
Text_iterator( list<Line>::iterator ll, Line::iterator pp ):ln(ll),pos(pp) {
}
char& operator *() {
return *pos;
}
Text_iterator & operator++() {
if ( pos == ln->end() ){
++ln;
pos = ln->begin();
}
else {
++pos;
}
The problem seems to be here. operator++ should not return the ln->end()
iterator, but it does. The one-past-the-end element will contain
arbitrary garbage, so you might even get an Access Violation when you
try to print the returned iterator (most of the time, I got an
additional question mark symbol at the beginning of each printed line,
but once I also got an Access Violation).
return *this;
}
bool operator ==( const Text_iterator &rhs ) const{
return ln == rhs.ln && pos ==rhs.pos;
}
bool operator != (const Text_iterator &rhs ) const{
return !(*this == rhs);
}
};
struct Document {
list<Line> line;
Document() {
line.push_back(Line());
}
Text_iterator begin() {
return Text_iterator(line.begin(),(line.begin())->begin() );
}
Text_iterator end() { //This is the main modification to
list<Line>::iterator last = line.end();
--last;
return Text_iterator(last, last->end());
//return Text_iterator(line.end(),(line.end())->end() );
}
};
This alteration is fine. However, it changes the behaviour (does not
print the last line) and does not fix the problem of the superfluous
character (see my comment above).
void print(Document &d) {
for (Text_iterator p = d.begin(); p != d.end(); ++p) {
cout << *p;
}
}
//Insert into Document
istream & operator>>(istream &is, Document &d) {
char ch;
while (is.get(ch)) { //This is also modified to read '\n' and space
d.line.back().push_back(ch);
if (ch == '\n') {
d.line.push_back(Line());
}
}
return is;
}
int main() {
Document dd;
cin>>dd;
print(dd);
return 0;
}
But while I ran the code with the following input I get extra character in output. That's the place I am perplexed.
Input
+++++++++
hello
how are you
I am fine
I
++++++++++
Output
hello
how are you
I am fine
I
a
++++++
So I am getting extra character "a" in output.
Could you please help me to understand the reason for this.
What you was experiencing was a fine example of Undefined Behaviour, I
got a different extra character, and sometimes the code even crashed
with an Access Violation. See my comments above.
Regards,
Stuart
PS: It is a pity that few implementation of the STL add extra checks for
debug mode. It would be no problem to use a special iterator for the
one-past-the-end elements which would raise an exception if they are
dereferenced. This would mean, that iterators needed to have a back-link
to the container in order to figure out whether it++ should return that
special iterator, but I think for hunting down bugs (such as yours) this
would be very neat.