The idea of this part of my code is relatively simple; I am doing a for loop that iterates over some range of integers, and the value of the iteration is placed within a number to string conversion and then called within the for loop to read a data file.
The code snippet:
for (int z = 11; z < 33; z++) {
const std::string filename_1 = "detection";
int value = z;
std::string filename_2;
std::ostringstream convert;
convert << value;
filename_2 = convert.str();
const std::string filename_3 = ".rat";
const std::string my_file = filename_1 + filename_2 + filename_3;
// Reading data from the .rat files of the detected signal.
Reading(my_file, times_det, signal_det);
// Further calculations go here.
The code compiles and executes, but after reading out two results of the calculations I am returned with the error:
./test
0.527679
0.639159
*** Error in `./test': double free or corruption (out): 0x0000000000f52a30 ***
Aborted (core dumped)
Am I not clearing memory where is necessary? Using .clear() did not remove this issue.
Thank you for the advice!
EDIT: The function 'Reading' for clarity:
void Reading(const std::string &filename, rarray<double,1> ×, rarray<std::complex<double>,1> &signal) {
std::ifstream f(filename.c_str());
// Read in the signal.
f >> times;
f >> signal;
}
#kam, I tried to reproduce the issue by using the following code and I am suspecting that it may have to do with the rarrays that you are using, but commented out as I don't have the details of the library you are using.
#include <iostream>
#include <fstream>
#include <strstream>
#include <sstream>
using namespace std;
void Reading(const std::string &filename, /*rarray< */double /*,1> */ ×, /* rarray<std::complex< */ double /*>,1> */ &signal) {
std::ifstream f(filename.c_str());
// std::ifstream f;
std::string ofile = "o_" + filename;
std::ofstream o;
//f.open(filename.c_str());
o.open(ofile.c_str());
// Read in the signal.
f >> times;
f >> signal;
cout << "file open :" << f.is_open() << " ";
cout << times << " " << signal << endl << flush;
//o << "file open :" << f.is_open() << " ";
o << times << " " << signal << endl << flush;
//f.close();
o.close();
}
int main(int argc, const char * argv[]) {
const std::string filename_1 = "detection";
const std::string filename_3 = ".rat";
double times_det = 0.0, signal_det = 0.0;
for (int z = 11; z < 33; z++) {
int value = z;
std::string filename_2;
std::ostringstream convert;
convert << value;
filename_2 = convert.str();
const std::string my_file = filename_1 + filename_2 + filename_3;
// Reading data from the .rat files of the detected signal.
Reading(my_file, times_det, signal_det);
// Further calculations go here.
}
return 0;
}
Related
Im trying to get a float value from a file.txt into a string. When I output that value with std::stof(str) it gets rounded. Example, in the text file there's "101471.71", whet i use the std::stof(str) it returns "101472", how to I avoid this?
Here's a part of that code (some parts are in spanish, sorry :p):
double CaptureLine(std::string filepath, int fileline, int linesize)
{
std::fstream file;
std::string n_str, num_n;
int current_line = 0, n_size, filesize = FileSize(filepath);
char ch_n;
double n_float = 0.0;
int n_line = filesize - fileline;
file.open("registros.txt");
if (file.is_open()) {
while (!file.eof()) {
current_line++;
std::getline(file, n_str);
if (current_line == n_line) break;
}
if (current_line < n_line) {
std::cout << "Error" << std::endl;
return 1;
}
file.close();
}
n_size = n_str.length();
for (int i = linesize; i < n_size; i++) {
ch_n = n_str.at(i);
num_n.push_back(ch_n);
}
std::cout << ">>" << num_n << "<<\n";
n_float = std::stof(num_n); //Here's the error
return n_float;
}
The issue probably isn't with std::stof, but is probably with the default precision of 6 in std::cout. You can use std::setprecision to increase that precision and capture all of your digits.
Here's a program that demonstrates:
#include <iostream>
#include <iomanip>
#include <string>
int main() {
std::cout << 101471.71f << "\n";
std::cout << std::stof("101471.71") << "\n";
std::cout << std::setprecision(8) << 101471.71f << "\n";
std::cout << std::stof("101471.71") << "\n";
return 0;
}
Outputs:
101472
101472
101471.71
101471.71
Be aware that std::setprecision sticks to the std::cout stream after it's called. Notice how the above example calls it exactly once but its effect sticks around.
The output of the code show gibberish values for all the variables of the Student struct. When the display function is ran.
I've include the relevant code in each of the add and display function for the binary file.
For the second function, does the seekg pointer automatically move to read the the next record each time the for loop runs?
//Student struct
struct Student
{
char name [30];
float labTest;
float assignments;
float exam;
};
//Writing function
afile.open(fileName,ios::out|ios::binary);
Student S;
strcpy(S.name,"test");
S.labTest = rand()%100+1;
S.assignments = rand()%100+1;
S.exam = rand()%100+1;
afile.write(reinterpret_cast<char*>(&S),sizeof(S));
afile.close();
//Reading function
afile.open(fileName,ios::in|ios::binary);
afile.seekg(0,ios::end);
int nobyte = afile.tellg();
int recno = nobyte / sizeof(Student);
Student S;
//Loop and read every record
for(int i = 0;i<recno;i++)
{
afile.read(reinterpret_cast<char*>(&S),sizeof(S));
cout << "Name of Student: " << S.name << endl
<< "Lab mark: " << S.labTest << endl
<< "Assignment mark: " << S.assignments << endl
<< "Exam mark: " << S.exam << endl << endl;
}
afile.close();
There are a lot of problems with your code:
Calling your write function will permanently overwrite the last written data set. You have to add: ios::append, so that new data will be written behind the last data you wrote before.
After you move with afile.seekg(0,ios::end); to get with tellg the file size, you have to go back to the start of the file before reading with afile.seekg(0,ios::beg)
It looks that you use a char array to store a string. This is not c++ style! And it is dangerous how you use it. If you use strcpy, you can copy a string which is longer than the space you reserved for it. So you should prefer std::string for that. But you can't simply write a struct which constains std::string as binary! To get checked copy you can use strncpy, but that is still not c++ ;)
For the second function, does the seekg pointer automatically move to read the the next record each time the for loop runs?
Yes, the file position moves which each successful read and write.
A general remark writing binary data by simply dumping memory content:
That is not a good idea, because you can only read that data back, if you use the same machine type and the same compiler options. That means: A machine with different endianness will read data totally corrupted. Also a different integer type ( 32 bit vs 64 bit ) will break that code!
So you should invest some time how to serialize data in a portable way. There are a lot of libraries around which can be used to read/write also complex data types like std::string or container types.
A hint using SO:
Please provide code which everybody can simply cut and paste and compiled. I did not know what your Student struct is. So I take a lot of assumptions! Is your struct really using char[]? We don't know!
#include <iostream>
#include <fstream>
#include <cstring>
const char* fileName="x.bin";
struct Student
{
char name[100]; // not c++ style!
int labTest;
int assignments;
int exam;
};
// Writing function
void Write()
{
std::ofstream afile;
afile.open(fileName,std::ios::out|std::ios::binary|std::ios::app);
Student S;
strcpy(S.name,"test"); // should not be done this way!
S.labTest = rand()%100+1;
S.assignments = rand()%100+1;
S.exam = rand()%100+1;
afile.write(reinterpret_cast<char*>(&S),sizeof(S));
afile.close();
}
void Read()
{
//Reading function
std::ifstream afile;
afile.open(fileName,std::ios::in|std::ios::binary);
afile.seekg(0,std::ios::end);
int nobyte = afile.tellg();
int recno = nobyte / sizeof(Student);
afile.seekg(0, std::ios::beg);
Student S;
//Loop and read every record
for(int i = 0;i<recno;i++)
{
afile.read(reinterpret_cast<char*>(&S),sizeof(S));
std::cout << "Name of Student: " << S.name << std::endl
<< "Lab mark: " << S.labTest << std::endl
<< "Assignment mark: " << S.assignments << std::endl
<< "Exam mark: " << S.exam << std::endl << std::endl;
}
afile.close();
}
int main()
{
for ( int ii= 0; ii<10; ii++) Write();
Read();
}
EDIT. Apparently, I was a bit too late in responding. Klaus has compiled a better, more comprehensive response dwelling into other problems regarding C-style char [], std::string and the endianness of the platform.
You should append to the file opened for every record. In your code you don't have this, at all. Please write the code in a way we can copy and paste, and test. As a working example, you should write some code that can be compiled and run as below:
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
// Student struct
struct Student {
char name[30];
float labTest;
float assignments;
float exam;
};
// Serializer
void serialize_student(const Student &s, const std::string &filename) {
// Append to the file, do not overwrite it
std::ofstream outfile(filename, std::ios::binary | std::ios::app);
if (outfile)
outfile.write(reinterpret_cast<const char *>(&s), sizeof(Student));
}
// Deserializer
std::vector<Student> deserialize_students(const std::string &filename) {
std::ifstream infile(filename, std::ios::binary);
std::vector<Student> students;
Student s;
while (infile.read(reinterpret_cast<char *>(&s), sizeof(Student)))
students.push_back(std::move(s));
return std::move(students);
}
int main(int argc, char *argv[]) {
// Generate records
std::vector<Student> mystudents;
std::generate_n(std::back_inserter(mystudents), 10, []() {
Student s;
std::strcpy(s.name, "test");
s.labTest = rand() % 100 + 1;
s.assignments = rand() % 100 + 1;
s.exam = rand() % 100 + 1;
return s;
});
// Print and write the records
for (const auto &student : mystudents) {
std::cout << student.name << ": [" << student.labTest << ','
<< student.assignments << ',' << student.exam << "].\n";
serialize_student(student, "students.bin");
}
// Read and print the records
auto records = deserialize_students("students.bin");
std::cout << "===\n";
for (const auto &student : records)
std::cout << student.name << ": [" << student.labTest << ','
<< student.assignments << ',' << student.exam << "].\n";
return 0;
}
I created a vector of vector (10*10000) and try to access this vector through member function. but I got a segmentation fault. I don't know what's wrong here...
Here is Simple.h
class Simple
{
private:
std::vector<double> data_row;
std::vector<std::vector<double> > data;
public:
Simple():data_row(10000), data(10, data_row){};
/*initialize data vector*/
int getSampleCounts(std::istream &File);
/*return number of packet samples in this file*/
Result getModel(std::istream &File);
/*return average and variance of simple delta time*/
void splitData (std::istream &File, const int & sample_in_fold);
};
#endif /* SIMPLE_H */
here is Simple.cpp
void Simple::splitData(std::istream& File, const int & sample_in_fold) {
double value = 0.0;
bool isFailed = true;
int label = 0;
while (File >> value) {
// for each value, generate a label
srand(time(NULL));
label = rand() % 10; // generate label between 0 to 9
while (isFailed) {
// segmentation fault in the next line!
std::cout << "current data size is: " << this->data.size() <<endl;
std::vector<double>::size_type sz = this->data[label].size();
if (sz <= sample_in_fold) {
std::cout << "current size is " << sz << "< samples in fold: " << sample_in_fold << endl;
this->data[label].push_back(value);
std::cout << "push_back succeed!" << endl;
isFailed = false;
} else {
std::cout << "label " << label << "if full. Next label. \n";
srand(time(NULL));
label = rand() % 10;
sz = this->data[label].size();
}
}
}
}
and I'm attaching the main file here.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib> // for system())
#include <sys/types.h>
#include <dirent.h>
#include <vector>
#include <limits.h> // for PATH_MAX
#include "Complex.h"
#include "Result.h"
#include "Simple.h"
#include <math.h>
using namespace std;
int main(int argc, char ** argv) {
struct dirent *pDirent;
DIR *pDir;
std::string line;
// check for args
if (argc == 1) {
printf("Usage: ./main + folder name. \n");
return 1;
}
pDir = opendir(argv[1]);
if (pDir == NULL) {
printf("Cannot open directory '%s' \n", argv[1]);
return 1;
}
// readdir returns a pointer to the next direcctory entry dirent structure
while ((pDirent = readdir(pDir)) != NULL) {
// get file name and absolute path
char *name = pDirent->d_name;
char buf[PATH_MAX + 1];
realpath(name, buf);
// std::cout << "Current file is: " << (pDirent->d_name) << endl;
if (has_suffix(pDirent->d_name, ".txt")) {
printf("[%s]\n", pDirent->d_name);
//printf("absolute path is %s. \n", buf);
ifstream infile;
// open file with absolute path
infile.open(buf, ios::in);
if (!infile) {
cerr << "Can't open input file " << buf << endl;
exit(1);
}
//processing for simple pattern
if (has_suffix(name, "testfile.txt")) {
Simple* simple_obj;
int number = simple_obj->getSampleCounts(infile);
Result simplerst = simple_obj->getModel(infile);
std::cout << "Number of delta time is " << number << endl;
infile.clear();
infile.seekg(0);
write_to_file(pDirent->d_name, simplerst);
// divide data into k = 10 folds, get number of data in each fold
int sample_in_fold = floor(number / 10);
std::cout << sample_in_fold << std::endl;
simple_obj->splitData(infile, sample_in_fold);
}
} else {
// printf("This is not a txt file. Continue\n");
}
}
closedir(pDir);
return 0;
}
And here is a sample testfile.txt. I only copied part of the original file, for illustration.
10.145906000
10.151063000
10.131083000
10.143461000
10.131745000
10.151285000
10.147493000
10.123198000
10.144975000
10.144484000
10.138129000
10.131634000
10.144311000
10.157710000
10.138047000
10.122754000
10.137675000
10.204973000
10.140399000
10.142194000
10.138388000
10.141669000
10.138056000
10.138679000
10.141415000
10.154170000
10.139574000
10.140207000
10.149151000
10.164629000
10.106818000
10.142431000
10.137675000
10.204973000
10.140399000
10.142194000
10.138388000
10.141669000
10.138056000
10.138679000
10.141415000
Here is Result.h
#ifndef RESULT_H
#define RESULT_H
typedef struct Result {
double average;
double sigma;
}Result;
and getModel function in Simple.cpp:
Result Simple::getModel(std::istream &File) {
double value = 0.0;
double average = 0.0;
double sum = 0.0;
double counter = 0.0;
double sumsqr = 0.0;
double var = 0.0;
double sigma = 0.0;
while (File >> value) {
++counter;
sum += value;
sumsqr += value * value;
}
average = sum / counter;
var = sumsqr / counter - average * average; //E(x^2) - (E(x))^2
sigma = sqrt(var);
std::cout << "average is " << average << std::endl;
std::cout << "std deviation is " << sigma << std::endl;
File.clear();
File.seekg(0);
Result result = {average, sigma};
return result;
}
One issue right away:
Simple* simple_obj;
int number = simple_obj->getSampleCounts(infile);
simple_obj is an uninitialized pointer, thus your program exhibits undefined behavior at this point.
Why use a pointer anyway? You could have simply done this to avoid the issue:
Simple simple_obj;
simple_obj.getSampleCounts(infile);
Also, this line may not be an issue, but I'll mention it anyway:
Result simplerst = simple_obj->getModel(infile);
We already know that in your original code, simple_obj is bogus, but that's not the issue here. If Result is an object, and that object does not have correct copy semantics, then that assignment will also cause undefined behavior.
You've got a couple of uses of endl without specifying std::endl (they're not the same thing - you always have to type the std:: ). Is endl silently referring to another variable somewhere else?
I am almost done with my project, but I still have one small thing that needs to be done...I need to run the entire program for each file in the directory. There are about 200 files in total. Below is the main class of the program that needs to run. I'm thinking I will put the entire thing in a do-while loop and run it until there are no more .dat files in the directory, but I'm not sure if that will work. Obviously, I'd like to replace the hard-coded file names with variables...I'm just not sure how to do that, either. Please let me know if you need clarification. I've been working on this project for a while and I'm getting kind of brain-numb. Thanks in advance for your help!
Edit My test directory is on a Windows machine, but it will be uploaded to a linux machine at school.
int main() {
NearestNeighbor face;
//string path = "C:\Users\Documents\NetBeansProjects\CSCE350";
//string searchPattern = "*dat";
// string fullSearchPath = path + searchPattern;
/*TEMPLATE DATA*/
/***********************************************************************************/
fstream templateData;
double data = 0.0;
templateData.open("003_template.dat", std::ios::in);
//check that the file is opened
if (!templateData.is_open()) {
std::cerr << "Template: Nooooooo!\n";
exit(0);
}
/*************************************************************************************/
//fill the templateVector with the values from templateData
std::vector<std::vector<double> > templateVector;
std::string line;
while (getline(templateData, line, '\n'))
templateVector.push_back(face.splitData(line));
//testing the contents of the templateVector
// cout << "TemplateVector: ";
// for (unsigned i = 0u; i != templateVector.size(); ++i) {
//
// std::cout << "Index[" << i << "] ";
// for(double value : templateVector[i])
// std::cout << value << " ";
// std::cout << "\n";
// }
/*QUERY DATA*/
/************************************************************************************/
std::ifstream inFile("003_AU01_query.dat", std::ios::in);
std::vector<double> queryVector;
double pixel = 0.0;
// Check that the file opened
if (!inFile.is_open()) {
std::cerr << "Query: Nooooooo!\n";
exit(1);
}
// fill the queryVector with the query data
while (inFile >> pixel) {
queryVector.push_back(pixel);
}
inFile.close();
// testing the content of the query vector
// for (unsigned i =0u; i < pixels.size(); i++){
// std::cout << "Index["<< i << "] " << pixels[i];
// }
// std::cout << "\n";
/*OUTPUT SCALAR PRODUCT*/
/****************************************************************************************/
vector<double> theList;
/*break out each of the vectors from the templateVector and compute the scalar product*/
for (auto& vec : templateVector) {
int i;
cout << "\nscalar_product: Index[" << i << "] " << face.scalar_product(vec, queryVector);
theList.push_back(face.scalar_product(vec, queryVector));//fill theList vector with the computations
i++;
std::cout << "\n";
}
//make sure that the sorted products are output with their original index numbers
vector<pair<int, double> > sorted;
sorted.reserve(theList.size());
for(size_t i = 0.00; i != theList.size(); i++){
sorted.push_back(make_pair(theList[i], i));
}
//sort the scalar products and print out the 10 closest neighbors
face.quickSort(sorted);
cout << "\nVector after sort:\n";
for(size_t i = 0; i < 10; i++){
cout << "idx: " << sorted[i].second << " " << "val: " << sorted[i].first << endl;
}
}
A solution in bash:
#!/bin/bash
for file in `ls`
do
./program $file
done
Of course you'd have to modify your main function to take an argument to pass to the fstream constructor:
int main(int argc, char **argv)
{
if (argc != 2)
{
// some error handling code
}
ifstream templateData(argv[1]);
if (!templateData)
{
// more error handling
}
// process the file
}
From your code it is windows.
This code will print all the *.dat file names in your folder:
Instead of printing do whatever you like.
first You'll need to include:
#include <windows.h>
Now to the code:
const wstring dir = L"C:\\Users\\Documents\\NetBeansProjects\\CSCE350";
const wstring ext = L"dat";
wstring findstr = dir;
findstr += L"\\*.";
findstr += ext;
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(findstr.c_str(),&ffd);
do{
if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
wstring path = dir;
path += L"\\";
path += ffd.cFileName;
wcout<< path<<endl;
}
} while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
EDIT:
On linux you can give your program a parameter path/to/dir/*.dat and you'll get the parameters trough argv, maybe its the better solution.
But if you insist to do it with code it is like this:
includes:
#include <sys/types.h>
#include <dirent.h>
Now the code:
const string dirname = "path/to/dir";
const string ext = ".dat";
DIR *dir;
struct dirent *de;
if((dir = opendir(dirname.c_str())) == NULL) {
//error... check errno and so on
cerr<<"Error..."<<endl;
}else{
while ((de = readdir(dir)) != NULL) {
//you can use stat to check if is is file or dir...
string filename(de->d_name);
if(ext = filename.substr(filename.size()-ext.size())){
cout<<dirname<<"/"<<filename<<endl;
}
}
closedir(dp);
}
Good luck
I'm writing to a file using binary/direct access. Works like a charm in 2008, but creates an exception in 2010 at runtime on line 128: Unhandled exception at 0x535dad54 (msvcp100d.dll) in HovedProsjekt.exe: 0xC0000005: Access violation writing location 0xfeeefeee.
Clicking the error takes me to xutility, where line 201: _Pnext != 0; *_Pnext = (_Pnext)->_Mynextiter) is next to be executed. I looked at microsofts "breaking changes" page with no luck. I am copy/pasting the entire code in cleartext, so no outdated libraries. I have tried all combinations of enabling and disabling _HAS_ITERATOR_DEBUGGING and _SECURE_SCL. I changed my question on advice from another user to trim my code down.
//Miniprosjekt.cpp
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool sjekkForOverskriving(void);
void LagFil(void);
void LeggTil();
void skrivUtFeil();
class Feil{
friend ostream& operator<<(ostream&, Feil);
friend istream& operator>>(istream&, Feil&);
protected:
int ID;
int prioritet;
string dato;
char beskrivelse[300];
char skrevetAv[30];
public:
Feil();
Feil(int, int, string, string, string);
};
Feil::Feil(){ //Default constructor
ID = 0;
prioritet = 1;
dato = "01.01.1900";
beskrivelse[0] = ' ';
skrevetAv[0] = ' ';
}
Feil::Feil(int id, int pri, string d, string beskr, string navn){ //Constructor
ID = id;
prioritet = pri;
dato = d;
strcpy(beskrivelse, beskr.c_str());
strcpy(skrevetAv, navn.c_str());
}
ostream& operator<<(ostream& out, Feil enfeil) //Overloader << operator, allowing for: cout << Feil afeil
{
out << "Id nr: " << enfeil.ID << "\nSkrevet av: " << enfeil.skrevetAv << "\nDato: " <<
enfeil.dato << "\nPrioritet: ";
if(enfeil.prioritet == 1)out << "Lav";
else if(enfeil.prioritet == 2)out << "Middels";
else out << "Høy";
out << "\nBeskrivelse:\n" << enfeil.beskrivelse << endl;
return out;
}
istream& operator>>(istream& in, Feil& enfeil) //Overloader >> operator: allowing for cin >> Feil afeil
{
in >> enfeil.ID >> enfeil.dato >> enfeil.beskrivelse >> enfeil.skrevetAv;
return in;
}
int main(void){
LagFil();
LeggTil();
skrivUtFeil();
return 0;
}
void LagFil(void){ //Creates a file with 500 empty "feil" objects
const int MAXFEIL = 500;
Feil enfeil;
ofstream utFil;
utFil.open("FeilTeller.dat");
utFil << 0;
utFil.close();
utFil.open("Feilmeldinger.dat", ios::out | ios::binary);
for(int a = 0; a <= MAXFEIL; a++){ //Fills the file with empty "Feil" objects
utFil.write(reinterpret_cast <const char*>(&enfeil), sizeof(enfeil));
}
utFil.close();
}
void LeggTil(){
int ID;
ifstream innFil;
innFil.open("FeilTeller.dat");
innFil >> ID;
innFil.close();
fstream fil;
fil.open("FeilTeller.dat");
ID++; //Opens feilteller.dat, reads how many objects have already been created. Adds one to that to append.
fil << ID;
fil.close();
int pri = 1;
string beskrivelse = "test";
string dato = "test2";
string skrevetAv = "test3";
Feil enfeil(ID, pri, dato, beskrivelse, skrevetAv);
fil.open("Feilmeldinger.dat", ios::out | ios::in | ios::binary);
fil.seekp((ID - 1) * sizeof(enfeil));
fil.write(reinterpret_cast <const char*>(&enfeil),
sizeof(Feil));
fil.close();
}
void skrivUtFeil(){
int idnr = 1;
//for(int i = 0; i < 2; i++){
Feil enfeil;
int antallFeil;
ifstream innFil;
innFil.open("FeilTeller.dat");
innFil >> antallFeil;
innFil.close();
innFil.open("Feilmeldinger.dat", ios::in | ios::binary);
innFil.read(reinterpret_cast <char*>(&enfeil),
sizeof(Feil));
innFil.clear();
//Prints out Feil with ID "idnr"
innFil.seekg((idnr - 1) * sizeof(enfeil));
innFil.read(reinterpret_cast <char*>(&enfeil),
sizeof(Feil));
cout << enfeil << endl;
cout << "Totalt antall feil: " << antallFeil << endl;
system("pause");
innFil.close();
//}
} //Exception on this line
Your class Feil contains string dato, so it's not trivially copyable. Therefore it's illegal to write and read it as raw binary data.
What happens if you do it? std::string contains a pointer to character array, so you write its value, not content. When you read it, you read the same value into the pointer, but it's pointing to garbage.