c++ – Writing and reading complex class objects to a file

Question:

There was a problem. I studied absolutely everything I could find. I have re-read dozens of topics on stacoverflow, both in Russian and in English. But everything that I managed to find either does not work (due to the difference between my case and the case in the topic), or even from the wrong opera. Let me describe the goal and what I have already done to achieve it. I'll clarify right away, I'm not asking you to write code for me in any way, I just need advice, a direction on how exactly to implement what I need (by what methods), and I will search for them myself. So I have a class

class Legal
{
private:
std::string name;
std::string phone;
std::string address;
std::string date;
std::string ogrn;

public:
Legal(
    std::string name = "Название не указано",
    std::string phone = "Номер не указан",
    std::string address = "Адрес регистрации не указан",
    std::string date = "Дата основания не указана",
    std::string ogrn = "ЕГРН не указан"
    ) {
        this->name = name;
        this->phone = phone;
        this->address = address;
        this->date = date;
        this->ogrn = ogrn;
    }
void setName(std::string& name) { this->name = name; }
void setPhone(std::string& phone) { this->phone = phone; }
void setAddress(std::string& address) { this->address = address; }
void setDate(std::string& date) { this->date = date; }
void setOgrn(std::string& ogrn) { this->ogrn = ogrn; }

std::string getName() { return name; }

};

Next, I create a vector vecLegal, and with the user can create new "clients" by filling objects of this class. As a result, a vector of these same objects is obtained, in which information about "clients" is stored. I need all these objects from the vector to be saved to a file (txt, bin – it doesn't matter) and then can be read from it. A kind of database. I tried overloading operator <<, but in those examples the class instances were of type int and I was having problems with string. I tried to do serialization using boost, but I am not good at this and did not understand why it did not work. The best thing I have been able to achieve is

ofstream out_file("vector.bin", ios::binary | ios::out);
out_file.write((const char*)&vecToadd.front(), vecToadd.size()*sizeof(Legal));

These lines successfully create a vector.bin file, but for any attempts to read it into a vector, I received "Segmenting error (memory dump was flushed to disk)". Please tell me what I'm doing wrong and what steps should I take to solve my problem?

Answer:

You at least have not read this site – it has been said so many times about how to deal with such non-POD objects that I personally have already sore my teeth …

In your way, you write not the contents of the lines in your object, but their service fields. The string contains a pointer to memory allocated somewhere, which contains the information you are interested in. But you are trying to write just these pointers and other service fields …

It turns out something like this – the wife says to get ready for vacation and put in the trunk in the car, well, there, an inflatable mattress, a tent, barbecue and skewers – well, in general, junk. You put pieces of paper in the trunk with the words "Mattress – on the mezzanine", "Tent – on the balcony", etc. So you save it to a file …

Upon arrival at the place, he reads – take out of the wallet pieces of paper with the words where everything is. But worse than that, the closet is now completely different, the balcony too, so a sticking out from my wife is about the result of such storage and an attempt to open a tent, which does not exist …

A rough sketch, as I would write and read. Sketch – you need to add checks, etc. Functions can be converted into output statements, but I don't think this is the best way … Yes, I also omitted castes to char* for brevity, add it yourself. The functions themselves can also be optimized – for example, allocate memory directly in a line and read into it …

void writeStr(const string& s, ostream& f)
{
    int l = s.length();
    f.write(&l,sizeof(int));
    f.write(s.data(),l);
}

void readStr(string& s, istream&f)
{
    int l;
    f.read(&l,sizeof(int));
    char * str = new char[l+1];
    f.read(str,l);
    str[l] = 0;
    s = str;
    delete[] str;
}

Then writing to your class file looks like

void writeInf(const Legal&l,ostream&f)
{
    writeStr(l.name,f);
    writeStr(l.phone,f);
    ...
}

Well, and reading:

void readInf(Legal&l, istream&f)
{
    readStr(l.name,f);
    readStr(l.phone,f);
    ...
}

Like that…

Update

Here's a complete sample code:

#include <string>
#include <iostream>
#include <fstream>

using namespace std;

class Test
{
public:
    Test(const char * a = "",
         const char * b = "",
         const char * c = "")
        :a(a),b(b),c(c){}

    void write(ostream&f) const
    {
        writeStr(a,f);
        writeStr(b,f);
        writeStr(c,f);
    }
    void read(istream&f)
    {
        readStr(a,f);
        readStr(b,f);
        readStr(c,f);
    }


    friend ostream& operator << (ostream&f, const Test&t)
    {
        return f << "(" << t.a << "," << t.b << "," << t.c << ")";
    }

private:
    string a, b, c;
    static void writeStr(const string& s, ostream& f)
    {
        size_t l = s.length();
        f.write((const char*)&l,sizeof(size_t));
        f.write(s.data(),l);
    }
    static void readStr(string& s, istream&f)
    {
        size_t l;
        f.read((char*)&l,sizeof(size_t));
        char * str = new char[l+1];
        f.read(str,l);
        str[l] = 0;
        s = str;
        delete[] str;
    }
};

int main(int argc, const char * argv[])
{
    Test x("x","1","2"), y("y","3","4");
    Test u,v;
    cout << u << "\n" << v << "\n\n";

    {
        ofstream out("data",ios::binary);
        x.write(out);
        y.write(out);
    }
    {
        ifstream in("data",ios::binary);
        u.read(in);
        v.read(in);
    }
    cout << u << "\n" << v << "\n\n";

}
Scroll to Top