Search code examples
c++vectoriteratorfstream

Ifstream is not able to read a vector from a file


Hello I am making a simple program which should make an abstract farm with some abstract animals but I have got a problem with reading vector from a file. I was translating most of the project and I deleted some I think unimportant functions and constructors. The program works fine when you 1st time load the vector but it fails after 2nd, 3rd... start. It fails when you try to load farm froma before created file. I am sorry for my english.

this code should be in classes.cpp - i don't know how to write it here

    #include<iostream>
    #include<string>
    #include<vector>
    #include<iterator>
    #include<fstream>
    #include<stdlib.h>
    using namespace std;

//  declaration of class zviera(animal)

    class zviera;

//  class farm

    class farma{ 
    private :

//  meno(name)

        std::string meno;

//  rozloha(size) - perhaps 945.5 * 749.9 meters

        std::pair<double, double> rozloha;

//  vector of friend class zviera(animal)

        std::vector < zviera > zvery;
    public :

//  class zviera(animal) is friend class of farma

        friend class zviera;

//  constructor -----------------------------------------------------

        farma() : meno(""), rozloha(0, 0), zvery(0) {}

//  pridajZviera(addAnimal) to the vector

        void pridajZviera(zviera & z){ zvery.push_back(z); }
        friend std::ostream & operator<<(std::ostream & os, const farma & far);
        friend std::istream & operator>>(std::istream & is, farma & far);
    };

//  the class zviera(animal)

    class zviera{
    private:

//  druh(kind of animal)

        std::string druh;

//  pocet(number of the animals)

        int pocet;

//  sex of the animals

        int pohlavie;
    public:

//  samec(male), samica(female) the sex of the animal

        enum { samec = 0, samica = 1};

//  constructor

        zviera() :druh(""), pocet(0), pohlavie(0){}
        friend std::ostream & operator<<(std::ostream & os, const zviera & zver);
        friend std::istream & operator>>(std::istream & is, zviera & zver);
    };

//  classes.h

    #include"classes.cpp"

//  Writing values of an animal

    std::ostream & operator<<(std::ostream & os, const zviera & zver){
            os << "Kind of animal : " << zver.druh;
            os << "\nNumber of animals : " << zver.pocet;
            os << "\nSex of animal : " << (zver.pohlavie == zver.samec? "male" : "female");
            return os;
        }

//  Setting values of an animal

    std::istream & operator>>(std::istream & is, zviera & zver){
                std::cout << "Kind : ";
                is >> zver.druh;
                std::cout << "Number : ";
                is >> zver.pocet;
                std::cout << "sex(0 - male, 1 - female) : ";
                is >> zver.pohlavie;
                return is;
            }

//  Writing saved values of a farm

    std::ostream & operator<<(std::ostream & os, const farma & far){
        os << "Name of the farm : " << far.meno;
        os << "\nSize of the farm : " << far.rozloha.first << " * " << far.rozloha.second << "metres." << std::endl;
        os << "Animals on the farm : \n";
        std::vector < zviera >::const_iterator it = far.zvery.begin();
        for (; it != far.zvery.end(); it++){
            os << *it << "\n";
        }
        return os;
    }

//  Setting values of a farm 

    std::istream & operator>>(std::istream & is, farma & far){
        std::cout << "Meno farmy je : ";
        is >> far.meno;
        std::cout << "Rozloha farmy je(a * b metrov) : ";
        is >> far.rozloha.first;
        is >> far.rozloha.second;
        std::cout << " metrov.";
        return is;
    }

The main.cpp

    #include"classes.h"

        int main()
    {
        ofstream fout;
        ifstream fin;
        int temp = 0;
        int tmp = 5;
        int tomp = 0;
        string nazov;
        farma far;
        zviera zvero;
        while (cin){
            cout << "Hello would you like to load your farm from a file?(yes - 1, no - 0, end - 2) ";
            cin >> temp;
            switch (temp){
            case 0: 
                cout << "Write a name of a file to save your new farm : ";
                cin >> nazov;
                fout.open(nazov.c_str(), ios_base::out);
                cin >> far;
                fout.write((char*)&far, sizeof far);
                cout << "Would you like to add any animals to your farm?(0 - no, 1 - yes) ";
                cin >> tmp;
                while (tmp == 1){
                    switch (tmp){
                    case 1:cin >> zvero;
                    far.pridajZviera(zvero);

I meam the problem is probably here:

                    fout.write((char*)&zvero, sizeof zvero);
                    cout << "Would you like to add any animals to your farm?(0 - no, 1 - yes) ";
                    cin >> tmp;
                        break;
                    default: 
                        break;
                    }
                }
                fout.close();
                cout << "Do you wanna see your farm?(0 - no, 1 - yes) ";
                cin >> tomp;
                if (tomp == 1){
                    cout << far;
                }
                break;
            case 1:
                cout << "Enter name of the file in which is your farm : ";
                cin >> nazov;
                fin.open(nazov.c_str(), ios_base::in);

The problem may be also here I think

                fin.read((char*)&far, sizeof far);
                while (fin.read((char*)&zvero, sizeof zvero)){
                    far.pridajZviera(zvero);
                }
                cout << far;
                fin.close();
                break;
            case 2: exit(EXIT_SUCCESS);
            default: cout << "Wrong value. Enter 0,1 or 2.\n";
                break;
            }
        }

        return 0;
    }

Solution

  • read and write operations are like memcpy, they make a binary image of the object, and don't follow pointers to subobjects. So you can only use them for trivially copyable objects.

    std::vector and std::string are NOT trivially copyable. (Objects containing these types are NOT trivially copyable either.) For those, you'll need to fetch and store the length, followed by the data. For std::string, and std::vector where the element type is trivially copyable, you can use read and write to store the data en masse. Most objects will themselves need to be carefully serialized.