Hello there,

I'm learning file I/O in c++ ATM and I'm getting a strange problem when I'm (at least I think so) following a tutorial.

What I'm doing is simply writing a User object to a file
and then read that same object from the file. I'm doing this just to see that the file operations work.

Code below (place inside a member function of the User class):

#include <fstream>

fstream f("D:/users.bin", ios::in | ios::out | ios::binary);

User userpost = *this;
User readuserpost;

f.write(reinterpret_cast<char *>(&userpost), sizeof(userpost));

f.seekg(0, ios::beg);

f.read(reinterpret_cast<char *>(&readuserpost), sizeof(readuserpost));

f.close();

Now, the above works fine. But if I comment out the f.write() command, I get an access violation / segmentation error.
So, I try to comment out the f.seekg() command, and now it works fine again. But I want to be able to move through the file so I really need it :) What am I doing wrong?

Thanks!

There shouldn't be a problem here... i just created a simple program to open a file that contains some text in exactly the same mode as you, and called seekg(0, ios::beg) without a problem...

you could always try calling f.clear() before hand...

Chris

f.clear() didn't help much.

What I've discovered, though, is that the access violation occurs
when I try to call a member function of the class that I just read from the file. That is:

string temp1 = readuserpost.GetUsername();

Here is the User class:

class User
{
   private:
        string username;
        string password;
        bool isVerified;

   public:
        User();
        User(string un, string pw);
        string GetUsername();
        string GetPassword();
        bool VerifyWithDatabase();
        void WriteToFile();
};

I read something about that classes I use as posts in binary files only can have "visible data" (no pointers, virtual functions etc.), but it should be OK to have private variables and then use these functions to call them. Or am I completely wrong?

Edit: if i leave out f.clear() and write one post first, then read it, the function call is OK. Any ideas?

I should add that when I DON'T write to the file first, but just read,
I get "address xxxxxxxx out of bounds" when I watch my "readuserpost" member variables.
Also it doesn't work now even if I remove the seekg() command.

(I wasn't allowed to edit the previous post any more so sorry for the bump).

Sorry but I am going to disagree with Freaky_Chris for the second time in two days! I hope he realizes the I agree with him most of the time :)

Anyway, you MAJOR sin is to think that reading into a class which may or may-not allocate memory will work. Let us take an example:

class X
{
   int * array;
};

Now the size of class is undetermined. You don't know when the size will change. So NEVER do a binary read into a class/struct unless you have absolute certainty about the size. Practically that means no pointers to memory, no STL object (e.g. vector or string) since these reserve an unknown amount of memory, no classes with static objects.

In your case you read from User. And look it has std::string. And wait, std::string often uses reference counting and static members, so that you corrupt memory is no surprise.

Your best bet is to read each item one by one. e.g.

void write(std::ostream& OutS)  const
{
    OutS<<username<<std::endl;
    OutS<<password<<std::endl;
    OutS<<verified<<std::endl;
    return;
}

void
User::read(std::istream& Input)
{
    Input.getline(username,'\n');
    Input.getline(password,'\n');
    Input>>isVerified;
    return;
}

That will actually give you LESS bytes of output than a binary dump.

p.s. you had better add some error checking to the read method, and you could implement some operator<< and operator>> methods if you like.

[Note: To the experts: I know you can do the binary writing and reading but that is because you know exactly how to do it on a case by case basis. Everyone else say well clear.]

Comments
Hehe, agree with me when you have a reason. I' self taught so i lack alot of knowledge and college takes alot of time of my ability o read around. I always appreciate extra material to read

Whoa, I would NEVER have thought of that string issue if you wouldn't have told me. I'll look into it but just a few questions while we're at it:
1) How do you explain that it works when I first write to the file and then read,
but not when I skip the writing and just read from it? The file will contain exactly the same stuff in both cases.
2) With the "<<" thingies, you're suggesting I turn my binary file into a text file, don't you?
3) Can't the string issue be solved by using char arrays of predetermined size?

Thanks a lot, I'll let you know when I get it to work (or not)!

Whoa, I would NEVER have thought of that string issue if you wouldn't have told me. I'll look into it but just a few questions while we're at it:
1) How do you explain that it works when I first write to the file and then read,

Well that is not an easy question since my version of your code doesn't. BUT if when you read/write, you look like you may have caused string to reserve the same length. It is also possible that
you are writing junk to a piece of unused memory. (not that string is referenced counted, so you should check that changing the original AFTER your read/write doesn't change the string on the later -- that would be another unexpected corruption.

Note you may get different behaviour dependent on you compiler optimization flags, your compiler choice and which implementation of the STL you choose.

2) With the "<<" thingies, you're suggesting I turn my binary file into a text file, don't you?

Yes. But how can you tell the difference (AFTER it has been written)
of a binary file with the characters
"abc" or a text file with the characters "abc". :)


3) Can't the string issue be solved by using char arrays of predetermined size?

Yes -- Careful because that sort of thing is very easy to get wrong in different ways.

Got it work with text files now and will stick with that to avoid unnecessary trouble for the moment :)

But, and I wanna take the opportunity to ask this since you solved this so well for me: I'm not allowed to write to C:\ in Vista even though my UAC is turned off. You know why? With D:\ it works fine. How can I get around it?

Edit: I think what's wrong is my relative path. Trying with "db/users.txt" as a relative path does not work, while
for example D:\users.txt works fine. Any ideas?

I am glad that solved the problem.

The best thing to do is mark this thread as solved.
Then ask the question again in a new thread.

(I am really not the person to answer your questions, at lunch at work, my group were trying to figure out how many hours we had used each OS, I got to 50 for all MS systems in total, compared to 15000 for Linux. I have had a cushy life :) )

Apparently the file/program, whatever is located on the D drive in your computer, not the C. It may be that you've partitioned your drive or you have a external drive or something else. You should be able to go someplace to look at the drive contents in the computer. I don't have Vista so the details aren't know to me for sure. However in the two Windows versions I have at the moment you can go Start->Accessories->Windows Explorer to see a tree of the drives and click on the appropriate drive letter to see what's in there. You can get the same information with a slightly different display arrangement by going Start->MyComputer and clicking on the appropriate drive letter.

This question has already been answered. Start a new discussion instead.