0

I have a class Tort(representation of the cake), in the main() in the switch statement I call the function displayAllTorts() which should read the objects of Tort from the file (objects were written to the file upfront) and display them on the console. In the displayAllTorts() function, I create a Tort instance variable, read from the file to it, and then print it. However, after looping ends and for block ends, the destructor is called and an Exception - Memory access violation is thrown.

#pragma once
#include<iostream>
#include<fstream>
#include<string>
#include <vector>
#include <iomanip>

using namespace std;
enum {
    choice_Quit,
    choice_InitializeCake,
    choice_PrintCake,
    choice_SaveToFile,
    choice_InitializeFromFile,
    choice_CompareCakes,
    choice_SortingCakes,
    choice_SortingCakesFromFile,
    choice_DisplayAllTortsFromFile,
};

class Tort
{
private:
    static int countObj;
    int count_parts;
    string cream;
protected:
    string congratulation;
public:
    string name;
    Tort();
    Tort(string, string, string, int);
    Tort(const Tort&);
    ~Tort();

    void setName(string);
    void setCream(string);
    void setCongr(string);
    void setCountParts(int);

    string getName();
    string getCream();
    string getCongr();
    int getCountParts();

    void printTort(string);
    void dataToInstance();
    int writeInstance(string);
    int setInstance(string, int);
    void cut(int);
    void cut();
    static int getCountInst();


    friend ostream& operator<<(ostream& os, const Tort& t);
    friend istream& operator>>(istream& is, Tort& t);

    friend ofstream& operator<<(ofstream& ofs, const Tort& t);
    friend ifstream& operator>>(ifstream& ifs, Tort& t);

    bool operator<(const Tort& t);
    bool operator>(const Tort& t);
    bool operator==(const Tort& t);
    

};

int divide(vector<Tort>&cakes, int start, int end);
void Quick(vector<Tort>& cakes, int start, int end);
void printVector(const vector<Tort>& v);
bool FileExists(string filename);
int enter_number(const string);
int menu();
int getValidIndex(const vector<Tort>& cakes);
int read_cakes_from_file(vector<Tort>& cakes, string filename);
void displayAllTorts(string file_name);

int main()
{
    string f_name = "file.dat"; string f_name1 = "file1.dat";
    if (FileExists(f_name)) {
        const char* c_f_name = f_name.c_str();
        remove(c_f_name);
    }
    vector<Tort> cakes;
    cout << "Number of torts are " << Tort::getCountInst() << endl;
    int choice;
    while ((choice = menu()) != choice_Quit) {
        switch (choice) {
        case choice_InitializeCake:
        {
            Tort cake = Tort();
            cin >> cake;
            cakes.push_back(cake);

            break;

        }
        case choice_PrintCake:
        {
            if (cakes.empty()) {
                cout << "\nNo cake instances available!\n";

                break;
            }

            int index = getValidIndex(cakes);

            cout << cakes[index];

            break;
        }
        case choice_SaveToFile:
        {
            if (cakes.empty()) {
                cout << "\nNo cake instances available!\n";

                break;
            }

            int index = getValidIndex(cakes);

            if (cakes[index].writeInstance(f_name))
                cout << "\nCake instance saved to file!\n";

            break;
        }
        case choice_InitializeFromFile:
        {
            if (cakes.empty()) {
                cout << "\nNo cake instances available!\n";

                break;
            }

            int index = getValidIndex(cakes);

            Tort cake ;

            cake.setInstance(f_name, index);
            cout << "\nThe cake is initialized from file...";
            cakes.push_back(cake);

            break;
        }
        case choice_CompareCakes:
        {

            Tort cake1 = Tort("Chocolate", "Happy birthday", "no cream", 6);
            cake1.printTort("1");
            Tort cake2 = Tort("Chocolate", "Happy birthday", "no cream", 6);
            cake1.printTort("1");

            cout << boolalpha << "\nCake1 is equal to cake2 ?  " << (cake1 == cake2) << endl;

            Tort cake3 = Tort("Tiramisu", "Happy Wedding Day!", "no cream", 3);
            cake3.printTort("3");

            Tort cake4 = Tort("Napoleon", "Happy Mother's Day!", "no cream", 7);
            cake4.printTort("4");

            if (cake3 > cake4) {

                cout << endl << cake3.name << " cake has more parts than " << cake4.name << " cake." << endl;

            }else if (cake3 < cake4) {

                cout << endl << cake3.name << " cake has less parts than " << cake4.name << " cake." << endl;

            }else if (cake3 == cake4) {
                cout << endl << cake3.name << " cake has the same number of parts as " << cake4.name << " cake." << endl;
            }

            break;
        }

        case choice_SortingCakes:
        {
            if (cakes.empty()) {
                cout << "\nNo cake instances available!\n";

                break;
            }

            cout << "\nVECTOR BEFORE SORTING\n";
            printVector(cakes);

            Quick(cakes, 0, cakes.size() - 1);

            cout << "\nVECTOR AFTER SORTING\n";
            printVector(cakes);

            break;
        }

        case choice_SortingCakesFromFile:
        {
            vector<Tort> cakes1;

            if (read_cakes_from_file(cakes1, f_name1)) {
                cout<< "\nCakes saved from file to vector\n";
            }

            cout << "\nVECTOR BEFORE SORTING\n";
            printVector(cakes1);

            Quick(cakes1, 0, cakes1.size() - 1);

            cout << "\nVECTOR AFTER SORTING\n";
            printVector(cakes1);

            break;


        }
        case choice_DisplayAllTortsFromFile:
        {
            displayAllTorts(f_name1);
            break;
        }


        default: cout << "\nIncorrect choice.\n";
            break;
        }

        

    }

    cout << "\nExiting...\n";
    puts("End of Program!");


    return 0;
}

int Tort::countObj = 0;
Tort::Tort()
{
    count_parts = 1;
    name = "Chocolate Tort";
    congratulation = "Congratulations!";
    cream = "chocolate";
   // cout << "\nDefault constructor...\n";
    countObj++;
   // cout << "\nNumber of torts: " << getCountInst() << endl;
}

Tort::Tort(string name, string congratulation, string cream, int count1)
{
    count_parts = count1;
    this->name = name;
    this->congratulation = congratulation;
    this->cream = cream;
    //cout << "\nConstructor with parameters...\n";
    countObj++;
    //cout << "\nNumber of torts: " << getCountInst() << endl;
}

Tort::Tort(const Tort& A)
{
    count_parts = A.count_parts;
    name = A.name;
    congratulation = A.congratulation;
    cream = A.cream;
   // cout << "\nCopy constructor...\n";
    countObj++;
    //cout << "\nNumber of torts: " << getCountInst() << endl;
}

Tort::~Tort()
{
    //cout << "\nDestructor...\n";
    countObj--;
    //cout << "\nNumber of torts: " << getCountInst() << endl;
}

void Tort::setName(string name)
{
    this->name = name;
}

void Tort::setCream(string cream1)
{
    cream = cream1;
}

void Tort::setCongr(string congratulation)
{
    this->congratulation = congratulation;
}

void Tort::setCountParts(int count_parts)
{
    this->count_parts = count_parts;
}

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

string Tort::getCongr()
{
    return congratulation;
}

string Tort::getCream()
{
    return cream;
}

int Tort::getCountParts()
{
    return count_parts;
}

void Tort::printTort(string msg) 
{
    cout << "\nCake " << msg << endl
        << setw(10) << "Name: " << setw(15) << name
        << setw(10) << "| Number of parts: " << setw(3) << count_parts
        << setw(10) << "| Cream: " << setw(5) << cream
        << setw(10) << "| Congratulations: " << setw(5) << congratulation << endl;
}



void Tort::dataToInstance()
{
    cout << "\nEnter name: ";
    getline(cin, name);
    cout << "Enter congratulation: ";
    getline(cin, congratulation);
    count_parts = enter_number("number of parts");
    cout << "Enter cream: ";
    getline(cin, cream);
}



int Tort::writeInstance(string file_name) 
{
    ofstream f(file_name, ios_base::binary | ios_base::app);
    if (!f)
    {
        cout << "\nFile " << file_name << " is not found!";
        return 0;
    }

    f << *this;
    f.close();
    return 1;
}


int Tort::setInstance(string file_name, int position) 
{
    ifstream f(file_name, ios_base::binary);
    if (!f)
    {
        cout << "\nFile " << file_name << " is not found!";
        return 0;
    }

    f.seekg(position * sizeof(Tort));
    f >> *this;

    return 1;

}


void Tort::cut(int num) { 
    if (num <= 1) { cout << "\nThe Tort can't be cutted."; return; }

    count_parts += num;
    cout << "Cutting the Tort into " << count_parts << " parts." << endl;

}

void Tort::cut() { // зменшення кількості частин
    if (count_parts == 0) cout << "\nThe Tort has already been eaten.";
    else {
        count_parts--;
        cout << "\nThe Tort is cutted\n";
    }
}

int Tort::getCountInst() 
{
    return countObj;
}

int menu() {
    cout << "\n===========MENU===========\n\n" <<
        choice_Quit << " - EXIT\n\n" <<
        choice_InitializeCake << " - INITIALIZE THE CAKE\n" <<
        choice_PrintCake << " - PRINT CAKE\n" <<
        choice_SaveToFile << " - SAVE CAKE TO FILE\n" <<
        choice_InitializeFromFile << " - INITIALIZE CAKE FROM FILE\n" <<
        choice_CompareCakes << " - COMPARE CAKES\n" <<
        choice_SortingCakes << " - SORTING THE CAKES\n" <<
        choice_SortingCakesFromFile << " - SORTING CAKES FROM FILE\n" <<
        choice_DisplayAllTortsFromFile << " - ShowFILE\n";
       
    return enter_number("your choice");
}


int enter_number(const string msg)
{
    cout << "Enter " << msg << ": ";
    string res;
    getline(cin, res);
    try {
        return stoi(res);
    }
    catch (const exception& e) {
        cout << "Error: Invalid input. Please enter a numeric value." << endl;
        return 0;
    }
}

int getValidIndex(const vector<Tort>& cakes) { 
    int number;
    do {
        cout << "\nEnter the number of the cake to select (1-" << cakes.size() << "): ";
        cin >> number;
        cin.ignore();
    } while (number < 1 || number > cakes.size());
    return number - 1;
}

bool FileExists(string filename)
{
    ifstream file(filename);
    if (file.is_open())
    {
        return 1;
        file.close();
    }
    else
    {
        return 0;
    }
}


istream& operator>>(istream& is, Tort& t) {

    cout << "\nEnter name: ";
    getline(is, t.name);
    cout << "Enter congratulation: ";
    getline(is, t.congratulation);
    cout << "Enter cream: ";
    getline(is, t.cream);
    t.count_parts = enter_number("number of parts");
    return is;
}

ostream& operator<<(ostream& os, const Tort& t)
{
    os << "\nCake " << endl
        << setw(10) << "Name: " << setw(5) << t.name
        << setw(10) << "| Number of parts: " << setw(3) << t.count_parts
        << setw(10) << "| Cream: " << setw(5) << t.cream
        << setw(10) << "| Congratulations: " << setw(5) << t.congratulation << endl;

    return os;
}

ofstream& operator<<(ofstream& ofs, const Tort& t)
{
    ofs.write((char*)&t, sizeof(Tort));
    return ofs;
}

ifstream& operator>>(ifstream& ifs, Tort& t)
{
    ifs.read((char*)&t, sizeof(Tort));
    return ifs;
}



 bool Tort:: operator<(const Tort& t) {
     return count_parts < t.count_parts;
 }

 bool Tort :: operator>(const Tort& t) {
     return count_parts > t.count_parts;
 }

 bool Tort :: operator ==(const Tort& t) {
     return count_parts == t.count_parts && name == t.name && cream == t.cream && congratulation == t.congratulation;
 }


 void printVector(const vector<Tort>& v) {
     for (size_t i = 0; i < v.size(); i++) {
         cout << "Tort #" << i + 1 << ":" << endl;
         cout << v[i] << endl;
     }
 }


 int divide(vector<Tort>& cakes, int start, int end)
 {
     int i = start;
     int j = end;
     Tort pivot = cakes[(start + end) / 2];

     while (i <= j) {
         while (cakes[i] < pivot) {
             i++;
         }

         while (cakes[j] > pivot) {
             j--;
         }

         if (i <= j) {
             swap(cakes[i], cakes[j]);
             i++;
             j--;
         }
     }

     return i;
 }

 void Quick(vector<Tort>& cakes, int start, int end)
 {
     if (start >= end) {
         cout << "Less then 2 cakes in the vector.\n";
         return;
     }

     int index = divide(cakes, start, end);

     Quick(cakes, start, index - 1);
     Quick(cakes, index, end);
 }


 int read_cakes_from_file(vector<Tort>& cakes, string filename) {
     ifstream f(filename, ios::binary);
     if (!f.is_open()) {
         cout << "\nFile " << filename << " is not found!";
         return 0;
     }

     cakes.clear();
   

     f.seekg(0, 2);
     int n = (int)f.tellg() / sizeof(Tort);
     cout << "Number of cakes in the file = " << n << endl;
     f.seekg(0);
     Tort cake;
     for (int i = 0; i < n; i++) {
         

         cake = Tort();
         f >> cake;

         cout << "i = " << (i+1)<<  cake;
         cakes.push_back(cake);
         
     }

     f.close();
     return cakes.size();
 }


 void displayAllTorts(string file_name) { 
     ifstream f(file_name, ios_base::binary);

     if (!f.is_open()) {
         cout << "Failed to open file " << file_name << endl;
         return;
     }

     f.seekg(0, 2);
     int n = (int)f.tellg() / sizeof(Tort);
     cout << "Number of objects in the file = " << n << endl;
     f.seekg(0);
     Tort cake;
     for (int i = 0; i < n; i++) {

         f >> cake;
         cout << cake;
     }

     f.close();
 }

I try to print all objects from binary files to concole using function displayAllTorts() with overloaded ifstream >> . But when the Tort instance cake is going to be deleted after reading I have a exception - memory access violation.

Hudson
  • 312
  • 2
  • 18
  • have you tried to diagnose where the problem occurs? – user253751 May 09 '23 at 10:53
  • 2
    Binary `write` and `read` don't work for most class types, including `std::string`. The `string` hold a pointer to its data, and `write` only writes the pointer, not what is pointed to. When `read`ing it back in you just get a pointer that now points nowhere (access violation). – BoP May 09 '23 at 10:57
  • @user253751 yes , when for loop in displayAllTorts is comming to its end and destructor for the temporaty cake instance starts to work – Andrii Yavorovskii May 10 '23 at 16:42

0 Answers0