User defined I/O operators.

when I run the code below I get garbage output after reading the data from the text file and printing it out. I believe the problem is with my user defined input operator but I can't be sure. The data gets written to the text file just fine, as follows:
1
2
3
4
5
6
7
(1,1)
(2,2)
(3,3)
(4,4)
(5,5)
(6,6)
(7,7)


the data that gets input from the textfile and printed out at the end of main looks like this...

1
2
3
4
5
6
7
(2293248,2292968)
(2293540,2292968)
(2293540,2292968)
(2293540,2292968)
(2293540,2293532)
(2293540,2293532)
(2293540,2293532)



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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;

struct Point
{
    int x;
    int y;
};

ostream& operator<<( ostream& os, Point& p )
{
    return os << "(" << p.x << "," << p.y << ")";
}

istream& operator>>( istream& is, Point& p )
{
    int x, y;
    char ch1, ch2, ch3;
    is >> ch1 >> x >> ch2 >> y >> ch3;
    p = Point{x,y};
    return is;
}

int main()
{
    //read data from keyboard into vector op.
    vector<Point> op;
    int x, y;
    cout << "Enter 7 points\n";
    for( int i=0; i<7; i++ )
    {
        cin >> x >> y;
        op.push_back( Point{x,y} );
    }

    // write the data to the screen using user defined output operator
    for( Point p : op )
    {
        cout << p << "\n";
    }

    // write the data to a text file using user defined output operator
    ofstream ost( "data.txt" );
    for( Point p : op )
    {
        ost << p << "\n";
    }

    // read data from text file using user defined input operator
    vector<Point> ip;
    Point p;
    ifstream ist{ "data.txt" };
    for( int i=0; i<7; i++ )
    {
        ist >> p;
        ip.push_back( p );
    }

    // write data to screen using user defined output operator
    for( int i=0; i<ip.size(); i++ )
        cout << ip[i] << "\n";

    return 0;
}


when I strip my code down to the following, the input operator works fine and the data gets input from the text file and printed out properly. This puzzles me, since the remaining code has not changed.

If anyone can find where I am messing up, it would be most appreciated.

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
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;

struct Point
{
    int x;
    int y;
};

ostream& operator<<( ostream& os, Point &p )
{
    cout << "(" << p.x << "," << p.y << ")";
}

istream& operator>>( istream& is, Point& p )
{
    int x, y;
    char ch1, ch2, ch3;
    is >> ch1 >> x >> ch2 >> y >> ch3;
    p = Point{x,y};
    return is;
}

int main()
{
    // read data from text file using user defined input operator
    vector<Point> ip;
    Point p;
    ifstream ist{ "data.txt" };
    for( int i=0; i<7; i++ )
    {
        ist >> p;
        ip.push_back( p );
    }

    // write data to screen using user defined output operator
    for( int i=0; i<ip.size(); i++ )
        cout << ip[i] << "\n";

    return 0;
}


checkout if the file open and if the reading operations are successful.

The ofstream may not write to disk directly but use an intermediate buffer, in that case your file is empty when you try to read from it.
your remark about ofstream using an intermediate buffer proved to be right. I added an ost.close() to close the output stream before opening an input stream. This flushed the output buffer to file, and this time there was data for the input stream to read.

Thanks.
Last edited on
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <vector>
#include <fstream>

struct Point
{
    int x;
    int y;
};

// note: required for comparing vectors of points using ==
bool operator== ( Point a, Point b ) { return a.x == b.x && a.y == b.y ; }

// this is not really required in this particular program; just being decent
bool operator!= ( Point a, Point b ) { return !(a==b); }

std::ostream& operator<< ( std::ostream& os, const Point& p )
{ return os << '(' << p.x << ',' << p.y << ')'; }

std::istream& operator>>( std::istream& is, Point& p )
{
    int x, y;
    char ch1, ch2, ch3;

    if( is >> ch1 >> x >> ch2 >> y >> ch3 &&
        ch1 == '(' && ch2 == ',' && ch3 == ')' ) p = {x,y}; // validate
    else is.setstate( is.rdstate() | std::ios_base::failbit ) ; // input failed

    return is;
}

int main()
{
    //read data from keyboard into vector op.
    std::vector<Point> op;

    std::cout << "Enter points one by one, enter eof to end input\n";
    int x, y;
    while( std::cin >> x >> y ) op.push_back( { x, y } );

    // write the data to the screen using user defined output operator
    for( Point p : op ) std::cout << p << '\n';

    // write the data to a text file using user defined output operator
    // canonical: if the file was opened, write every object in the sequence to the file
    if( std::ofstream ost{ "data.txt" } ) for( Point p : op )   ost << p << '\n';
    else std::cerr << "error opening output file\n" ;
    // note: the output stream ost is destroyed when it goes out of scope

    // read data from text file using user defined input operator
    std::vector<Point> ip;
    Point p;
    if( std::ifstream ist{ "data.txt" } ) while( ist >> p ) ip.push_back(p) ;
    else std::cerr << "error opening input file\n" ;

    // verify that the two vectors are equal (lexicographically equal)
    if( ip == op ) std::cout << "read back the points successfully\n" ;
    else std::cerr << "error in i/o of point\n" ;

    // write data to screen using user defined output operator
    for( auto p : ip ) std::cout << p << '\n';
}

http://coliru.stacked-crooked.com/a/70f6c344641a7fb1


Using std::pair<> http://en.cppreference.com/w/cpp/utility/pair
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
47
48
49
50
51
52
53
54
#include <iostream>
#include <vector>
#include <fstream>
#include <utility>

using Point = std::pair<int,int> ;

std::ostream& operator<< ( std::ostream& os, const Point& p )
{ return os << '(' << p.first << ',' << p.second << ')'; }

std::istream& operator>>( std::istream& is, Point& p )
{
    int x, y;
    char ch1, ch2, ch3;

    if( is >> ch1 >> x >> ch2 >> y >> ch3 &&
        ch1 == '(' && ch2 == ',' && ch3 == ')' ) p = {x,y}; // validate
    else is.setstate( is.rdstate() | std::ios_base::failbit ) ; // input failed

    return is;
}

int main()
{
    //read data from keyboard into vector op.
    std::vector<Point> op;

    std::cout << "Enter points one by one, eof to end input\n";
    int x, y;
    while( std::cin >> x >> y ) op.emplace_back( x, y ); // construct Point directly in the vector
    // http://en.cppreference.com/w/cpp/container/vector/emplace_back

    // write the data to the screen using user defined output operator
    for( Point p : op ) std::cout << p << '\n';

    // write the data to a text file using user defined output operator
    // canonical: if the file was opened, write every object in the sequence to the file
    if( std::ofstream ost{ "data.txt" } ) for( Point p : op )   ost << p << '\n';
    else std::cerr << "error opening output file\n" ;
    // the output stream ost is destroyed when it goes out of scope

    // read data from text file using user defined input operator
    std::vector<Point> ip;
    Point p;
    if( std::ifstream ist{ "data.txt" } ) while( ist >> p ) ip.push_back(p) ;
    else std::cerr << "error opening input file\n" ;

    // verify that the two vectors are equal (lexicographically equal)
    if( ip == op ) std::cout << "read back the points successfully\n" ;
    else std::cerr << "error in i/o of point\n" ;

    // write data to screen using user defined output operator
    for( auto p : ip ) std::cout << p << '\n';
}

http://coliru.stacked-crooked.com/a/4cfa5281465e63c0
Topic archived. No new replies allowed.