aj3423
aj3423

Reputation: 2561

why stream keep reading and won't reach to eof?

I'm implementing a very simple serialization library, to save/restore user_info object, which contains an int and a std::string, here's my code:

#include <iostream>
#include <sstream>
using namespace std;

struct user_info {
    int id;
    string name;
};

// for any POD type like int, read sizeof(int) from the stream
template <class stream_t, class T>
void de_serialize(stream_t& stream, T& x) {
    stream.read((char*)&x, sizeof(T));
}

// for std::string, read length(int) first, then read string content when length>0
template <class stream_t>
void de_serialize(stream_t& stream, std::string& str) {
    int len;
    de_serialize(stream, len);
    str.resize(len);
    char x;
    for(int i=0; i<len; i++) {
        de_serialize(stream, x);
        str[i] = x;
    }
}

// read from stream, fill id and name
template <typename stream_t>
void de_serialize(stream_t& ss, user_info& ui) {
    de_serialize(ss, ui.id);
    de_serialize(ss, ui.name);
}


int main() {
    // read from file, but here I use a 8-bytes-content represents the file content
    stringstream ifs;
    // two int, \x1\x1\x1\x1 for id, \x0\x0\x0\x0 for name
    ifs.write("\x1\x1\x1\x1\x0\x0\x0\x0", 8);
    while(!ifs.eof()) {
        user_info ui;
        de_serialize(ifs, ui);
        // when first time goes here, the stream should've read 8 bytes and reaches eof, 
        // then break the while loop, but it doesn't
        // so the second time it calls de_serialize, the program crashes
    }
}

the code illustrates the part of de-serializing. The while loop is supposed to run once, and the stream reaches eof, but why it doesn't stop looping? The second loop causes a crash.

Please refer to the comments, thanks.

Upvotes: 0

Views: 273

Answers (1)

Galik
Galik

Reputation: 48615

The eof() flag will never be set if the streem develops an error condition. It is usually wrong to loop on eof(). What I would do here is change the return type from your de_serialize() function to return the stream and then rewrite your loop around the de_serialize() function

Like this:

#include <iostream>
#include <sstream>
using namespace std;

struct user_info {
    int id;
    string name;
};

// for any POD type like int, read sizeof(int) from the stream
template <class stream_t, class T>
stream_t& de_serialize(stream_t& stream, T& x) {
    stream.read((char*)&x, sizeof(T));
    return stream; // return the stream
}

// for std::string, read length(int) first, then read string content when length>0
template <class stream_t>
stream_t& de_serialize(stream_t& stream, std::string& str) {
    int len;
    de_serialize(stream, len);
    str.resize(len);
    char x;
    for(int i=0; i<len; i++) {
        de_serialize(stream, x);
        str[i] = x;
    }
    return stream; // return the stream
}

// read from stream, fill id and name
template <typename stream_t>
stream_t& de_serialize(stream_t& ss, user_info& ui) {
    de_serialize(ss, ui.id);
    de_serialize(ss, ui.name);
    return ss; // return the stream
}


int main() {
    // read from file, but here I use a 8-bytes-content represents the file content
    stringstream ifs;
    // two int, \x1\x1\x1\x1 for id, \x0\x0\x0\x0 for name
    ifs.write("\x1\x1\x1\x1\x0\x0\x0\x0", 8);

    user_info ui;
    while(de_serialize(ifs, ui)) { // loop on de_serialize()

        // Now you know ui was correctly read from the stream

        // when first time goes here, the stream should've read 8 bytes and reaches eof,
        // then break the while loop, but it doesn't
        // so the second time it calls de_serialize, the program crashes
    }
}

Upvotes: 1

Related Questions