Функция подгружает данные с файла. Перед каждой новой загрузкой пытаюсь почистить данные в массиве, чтобы подгрузить все заново. При этом на второй раз вылетает в точке delete[].
Вот и сама функция:
void uploadData(Person *& persons, int & size, std::string path) {
std::fstream fs;
fs.open(path, std::fstream::in);
if (!fs.is_open()) {
std::cerr << "Error with opening file. Try again\n";
}
else
{
if (persons != nullptr) {
delete[] persons;
}
MetaData metaData;
fs.read((char*)&metaData, sizeof(MetaData));
size = metaData.getSize();
persons = new Person[size];
for (int i = 0; i < size; i++) {
fs.read((char*)&persons[i], sizeof(Person));
}
std::cout << "Data was successfully uploaded\n";
}
fs.close();
}
А вот такая функция работает без проблем:
void check(Person *& persons) {
if (persons != nullptr) {
delete[] persons;
}
persons = new Person[2];
persons[0].setInfo();
}
Помогите добрые люди разобраться с ситуацией. А то что-то туплю уж не первый час
Код из main(), на котором крашится
int main() {
std::string path = "Storage.txt";
Person * a = nullptr;
int size = 0;
std::string todo;
for (;;) {
std::cout << ">>";
std::cin >> todo;
if (todo == "pushPerson") pushPerson(a, size);
if (todo == "showAll") showAll(a, size);
if (todo == "uploadData") uploadData(a, size, path);
if (todo == "saveData") saveData(a, size, path);
}
system("pause");
delete[] a;
return 0;
}
Класс Person вот:
class Person
{
public:
std::string getName();
int getAge();
int getSalary();
void setName(std::string name);
void setAge(int age);
void setSalary(int salary);
void setInfo();
void showInfo();
private:
int salary;
int age;
std::string name;
}
Вот это:
std::string name;
в составе класса Person делает недопустимым запись и чтение с помощью функций write и read из памяти. Потому что в name содержится, например, не сама строка, а указатель на нее. При записи вы сохраняете в файле какой-то адрес, потом считываете его - когда он уже давно не актуален, а при удалении вызов деструктора пытается удалить память по несуществующему адресу...
Такие классы нужно записывать и читать иначе - например, в вашем случае для int-поля можно писать и так, но вот name я бы писал так - сначала размер строки, потом содержимое. При чтении - читал размер, выделял буфер, в него читал строку, а потом уже инициализировал ею поле name.
Ну, или, если у вас C++17 - без промежуточного буфера, как описано тут.
С использованием The C++ Programming Language Special Edition 2015 Страуструпа (пункт 15.6.1 Выделение памяти под массивы):
#include <iostream>
//класс содержит только число
class Test
{
private:
int data;
public:
explicit Test(int a):data(a)
{
}
Test():data(0){}
void set(int a)
{
data = a;
}
void show()
{
std::cout<<data<<std::endl;
}
virtual ~Test(){}
};
void update(Test* array, int size, int times=1)
{
if(array != nullptr)
{
delete[] array;
}
array = new Test[size];
array[0].set(100*times); //обновление данных
array[1].set(200*times);
}
int main() {
auto p = new Test[2];
p[0].set(1);
p[1].set(2);
update(p, 2); // в первый раз умножаются данные на дефолт-значение, на 1
p[0].show();
update(p, 2, 2); // теперь на 2
p[0].show();
//Доказательство, что данные обновлены
delete p;
return 0;
}
Здесь представлен примитивно принцип работы Вашей программы. В книге в указанном пункте показывается такой пример инициализации массива:
void f(int s)
{
Employee* p = new Employee[s];
//...
delete[] p;
}
У Вас же массив инициализируется нулевым указателем:
Person * a = nullptr;
(Так же не забывайте про виртуальный деструктор, если Вы будете наследовать от этого класса)
Сборка персонального компьютера от Artline: умный выбор для современных пользователей