Ошибка нарушения доступа C ++

Я написал простую программу, чтобы научиться использовать произвольное заполнение. Он компилируется нормально, но во время выполнения выдает ошибку нарушения доступа. Я пишу и читаю только одну запись.

Заголовочный файл:

#include<iostream>
#include<string>
#include<fstream>
using namespace std;

#ifndef HEADER_H
#define HEADER_Hclass info
{
private:
int id;
string name;
public:
info(int = 0, string = " ");
void set(int, string);
void display();
void write();
void read();
};

#endif

Файл реализации:

#include<iostream>
#include<string>
#include<fstream>
#include"Header.h"using namespace std;

info::info(int x, string y)
{
set(x, y);
}

void info::set(int x, string y)
{
id = x;
name = y;
}

void info::display()
{
cout << "\n\n\tid : " << id;
cout << "\n\tname" << name;
}

void info::write()
{
ofstream o("info.dat", ios::out | ios::binary | ios::app);
info a(id, name);
info *p = &a;
o.write(reinterpret_cast<const char *>(p), sizeof(info));
o.close();
cout << "\n\n\tWrite Successful";
}

void info::read()
{
ifstream i("info.dat", ios::in | ios::binary);
i.seekg(0);
info a(0, "a");
info *p = &a;
i.read(reinterpret_cast<char *>(p), sizeof(info));
i.close();
p->display();
cout << "\n\n\tRead Successful";
}

Главный:

#include<iostream>
#include<string>
#include<fstream>
#include"Header.h"using namespace std;

void main()
{
info a(10, "muaaz");
a.write();
a.display();
info b(2, "m");
b.read();
}

Ошибка возникает после функции чтения. Функция cout «Read Successful» в конце функции read работает нормально, и после этого в main нет других операторов. Я не знаю, что является причиной ошибки.

-2

Решение

Каждый случай reinterpret_cast в вашем коде должен быть четкий намек на то, что происходит что-то опасное и подверженное ошибкам.

void info::write()
{
ofstream o("info.dat", ios::out | ios::binary | ios::app);
info a(id, name);
info *p = &a;
o.write(reinterpret_cast<const char *>(p), sizeof(info));
o.close();
cout << "\n\n\tWrite Successful";
}

Это не может работать правильно. Все вопросы языка юриста в стороне, рассмотрите точку зрения реализации здесь. std::string обычно непосредственно не содержит (как элемент данных) текст, который он представляет, но вместо этого содержит указатель динамически распределяемой памяти, где хранится текст.

Итак, что вы в итоге делаете, это записываете адрес памяти в файл.

Этого уже достаточно для того, чтобы подход был обречен на любую сериализацию, поскольку очевидно, что адреса памяти различны для разных запусков одной и той же программы.

Но это не сработает даже в этом простом примере, когда файл записывается и читается из одного и того же выполнения. a это локальный объект. когда write заканчивается, объект уничтожается, а вместе с ним std::string это содержит. Когда std::string уничтожается, память, выделенная для его содержимого, освобождается.

Следовательно, как только write сделано, ваш файл содержит неверный адрес памяти. Несколько мгновений спустя, в read функция, вы пытаетесь вставить этот неверный адрес в новый std::string, К счастью, вы получаете нарушение прав доступа, поэтому замечаете, что что-то не так. Если бы вам не повезло, программа какое-то время продолжала бы производить желаемое поведение, только чтобы потом начать сбой или делать странные вещи на более позднем этапе.


Некоторые вопросы, которые делают ситуацию еще более сложной:

  • Макет памяти std::string не определено стандартом C ++. Таким образом, разные компиляторы с разными настройками компилятора будут создавать разные info.dat файлы, даже если вы скомпилировали их из того же исходного кода C ++.

  • std::string может использовать или не использовать Small-String Optimization (SSO), метод, который означает, что для строк с несколькими символами текст является непосредственно хранится в объекте, а не динамически распределяется. Таким образом, вы даже не можете предположить наличие указателя.

  • С другой стороны, std::string может содержать даже Больше указатели на динамически выделенную память, указывающие на конец отображаемого текста и на конец выделенной памяти (для capacity функция-член).


Учитывая все эти важные внутренние сложности, вас не должно удивлять, что ваша попытка обойти или игнорировать их все с помощью простого reinterpret_cast Запускает неопределенное поведение.

Сериализация и особенно десериализация не POD-типов не легка в C ++[*] и еще не был стандартизирован. Вы можете рассмотреть стороннюю библиотеку. Как всегда, Boost стоит попробовать, когда дело доходит до сторонних библиотек, и, как оказалось, он содержит библиотеку сериализации, а именно Boost.Serialization.


[*] На самом деле, это нелегко ни на одном языке, даже на тех, которые делают это легко, например, на Java с его очень опасным Serializable интерфейс.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]