Reputation: 2561
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
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