i want to parse the content of a file and load into a map.
This is the file content format:
Movie-name release-year price cast ishd
"DDLG" 2010 20.00 "shahrukh and Kajal" true
"Aamir" 2008 10.00 "abc, xyz and ijkl" false
Key for map will be the first word (Movie name).
class defition:
class movieInfo
{
private:
int releaseYear;
double price;
string cast;
bool isHD;
};
This is the function i am trying to implement.
void fill_map_contents (map <string, movieInfo*> &mymap, ifstream& myfile)
{
string line;
string word;
while (getline(myfile, line))
{
out << "inside while loop " << line << endl;
stringstream tokenizer;
tokenizer << line;
movieInfo *temp = new movieInfo;
while (tokenizer >> word)
{
cout << " printing word :->"<< word << endl;
//temp->releaseYear = atoi(word);
//temp->price = 12.34;
//temp->cast = "sahahrukh salman";
//temp->isHD = false;
mymap[word] = temp;
}
delete temp;
}
}
I am not getting any idea, after while (tokenizer >> word), how to fill object variable and assign it to map.
Any help will be highly appreciated.
Devesh
cout << " printing word :->"<< word << endl;
//temp->releaseYear = atoi(word);
//temp->price = 12.34;
//temp->cast = "sahahrukh salman";
//temp->isHD = false;
in above code you are trying to access private members of the class directly which is not possible.Hence ,better solution is you should include public getter/setter for each variable as follows.
public:
void setreleaseYear(int sry){releaseYear=sry;}
void setprice(double pr){price=pr;}
void setcast(string cast){string=str;}
void setisHD(bool id){isHD=id;}
now use in place of commented code :
//temp->releaseYear = atoi(word);
temp->setreleaseYear(atoi(word));
tokenizer >> word;
//temp->price = 12.34;
temp->setprice(atof(word));
tokenizer >> word;
//temp->cast = "sahahrukh salman";
temp->setcast(word);
tokenizer >> word;
//temp->isHD = false;
temp->setisHD(word);
No need of while loop.
You must simplify things. I suggest to add inserction and extraction operator for movieinfo and choose new line as field separator
DDLG
2010
20.00
shahrukh and Kajal
true
Aamir
2008
10.00
abc, xyz and ijkl
false
class movieInfo
{
public:
int releaseYear;
double price;
string cast;
bool isHD;
friend std::ostream& operator << ( std::ostream& os, const movieinfo& i )
{
return os << i.releaseYear << '\n'
<< i.price << '\n'
<< i.cast << '\n'
<< std::boolalpha << i.isHD() << '\n';
}
friend std::istream& operator >> ( std::istream& is, movieinfo& i )
{
is >> i.releaseYear
>> i.price;
getline( is, i.cast );
return is >> std::boolalpha >> i.isHD;
}
};
void fill_map_contents (map <string, movieInfo> &mymap, ifstream& myfile)
{
while ( !myfile.eof )
{
string name;
myfile >> name;
movieInfo mi;
myfile >> m1;
mymap[ name ] = movieInfo;
}
}
note that I changed map <string, movieInfo*> in map <string, movieInfo> prefer using move semantic.
Another suggestion I will change moveinfo in:
class movieInfo
{
public:
// ctor and move, assign operator and move operator
int releaseYear() const { return mReleaseYear; };
double price() const { return mPrice; };
const string& cast() const { return mCast; };
bool isHD() const { return mIsHD; };
private:
int mReleaseYear;
double mPrice;
string mCast;
bool mIsHD;
friend std::ostream& operator << ( std::ostream& os, const movieinfo& i )
{
return os << i.releaseYear() << '\n'
<< i.price() << '\n'
<< i.cast() << '\n'
<< std::boolalpha << i.isHD() << '\n';
}
friend std::istream& operator >> ( std::istream& is, movieinfo& i )
{
is >> i.mReleaseYear
>> i.mPrice;
getline( is, i.mCast );
return is >> i.mIsHD;
}
};
You are effectively trying to parse a CSV file, with space as separator and " as quote character.
I'd recommend using a library for this, like this one.
Example code (taken from the help page):
// Note: I changed mymap to map<string, movieInfo> without a pointer - it's not
// needed
const char field_terminator = ' '; // Use a space
const char line_terminator = '\n'; // Use line break
const char enclosure_char = '"'; // Use "
csv_parser file_parser;
file_parser.set_skip_lines(1);
file_parser.init(filename);
file_parser.set_enclosed_char(enclosure_char, ENCLOSURE_OPTIONAL);
file_parser.set_field_term_char(field_terminator);
file_parser.set_line_term_char(line_terminator);
while(file_parser.has_more_rows()) {
csv_row row = file_parser.get_row();
movieInfo temp; // No need for pointers
temp->releaseYear = atoi(row[1]); // C++11: Use std::stoi()
temp->price = atof(row[2]); // C++11: Use std::stof()
temp->cast = row[3];
temp->isHD = row[4].compare("true") == 0;
mymap[row[0]] = temp;
}
Related
I create a multiple table of string type. I keep variables inside (int, string). It gives me an error:
[Error] cannot convert 'std::string {aka std::basic_string}' to 'char' in assignment
I've created a tree-shaped suite of functions.The program create a multiple array from a file with this format:
11 10 2001
CSKA Moscow
12 1
Bayern Munich
...
Program:
void llegir(std::fstream &_contingut, std::string *_taula) {
//declaro variables
int dia, mes, any, puntsLocal, puntsVisitant, i = 0;
std::string equipLocal, equipVisitant;
while (!(_contingut.eof())) {
//llegeixo arxiu
_contingut >> dia >> mes >> any; //primera linea
_contingut.ignore();
getline(_contingut, equipLocal); //segona linea
_contingut >> puntsLocal >> puntsVisitant; //tercera linea
_contingut.ignore();
getline(_contingut, equipVisitant); //quarta linea
_taula[i][0] = dia;
_taula[i][1] = mes;
_taula[i][2] = any;
_taula[i][3] = equipLocal.c_str();
_taula[i][4] = puntsLocal;
_taula[i][5] = equipVisitant.c_str();
_taula[i][6] = puntsVisitant;
i++;
}
}
void creartaulaDelFitxer(std::string _fitxer, std::string *_taula, int &n_taula) {
std::fstream arxiu;
arxiu.open(_fitxer, std::fstream:: in );
if (arxiu.is_open()) {
std::cout << "existeix";
} else {
std::cout << "ERROR OBERTURA FITXER";
}
llegir(arxiu, _taula);
}
int main(int argc, char** argv) {
std::string fitxer;
std::string eurolliga[300][7];
int n_taula = 0;
std::cout << "INTRODUEIX NOM FITXER:" << std::endl;
std::cin >> fitxer;
creartaulaDelFitxer(fitxer, *eurolliga, int n_taula);
}
You are mixing pointers, chars and strings which will certainly cause a lot of headache. Try to use the standard containers, like std::string and std::vector. If you need many strings, put them in a vector. When you have a collection of data like
11 10 2001
CSKA Moscow
12 1
Bayern Munich
that describes some entity, create a class for it. You can then add streaming operators for that class to read in one of these entities. If you have a collection of entities, make a container and add streaming operators for that too.
Example:
#include <iostream>
#include <fstream>
#include <vector>
class Game {
std::string equipLocal{};
std::string equipVisitant{};
int dia{}, mes{}, any{};
int puntsLocal{}, puntsVisitant{};
public:
friend std::istream& operator>>(std::istream&, Game&);
friend std::ostream& operator<<(std::ostream&, const Game&);
};
// read one entity from an istream
std::istream& operator>>(std::istream& is, Game& g) {
if(is >> g.dia >> g.mes >> g.any) {
is.ignore();
if(std::getline(is, g.equipLocal) && (is >> g.puntsLocal >> g.puntsVisitant)) {
is.ignore();
std::getline(is, g.equipVisitant);
}
}
return is;
}
// write one entity to an ostream
std::ostream& operator<<(std::ostream& os, const Game& g) {
return os << g.dia << " " << g.mes << " " << g.any << "\n"
<< g.equipLocal << "\n"
<< g.puntsLocal << " " << g.puntsVisitant << "\n"
<< g.equipVisitant << "\n";
}
class EuroLiga {
std::vector<Game> games{};
public:
bool Load(const std::string& filename) {
std::ifstream arxiu(filename);
if(arxiu) {
games.clear();
arxiu >> *this; // use this class' friend, operator>>
return true;
} else
return false;
}
// support for basic non-const iteration over the 'games'
std::vector<Game>::iterator begin() { return games.begin(); }
std::vector<Game>::iterator end() { return games.end(); }
friend std::istream& operator>>(std::istream&, EuroLiga&);
};
// read all entities from an istream
std::istream& operator>>(std::istream& is, EuroLiga& el) {
Game tmp;
while(is >> tmp) {
el.games.push_back(std::move(tmp));
}
return is;
}
int main() {
EuroLiga euroliga;
std::string fitxer;
std::cout << "INTRODUEIX NOM FITXER: ";
std::cin >> fitxer;
euroliga.Load(fitxer);
// display all entities read from the file
for(auto& g : euroliga) {
std::cout << g << "\n";
}
}
void llegir(std::fstream &_contingut, std::string *_taula)
Gets a pointer to a string called _taula, this is probably your array.
However you assign something to your array like this:
_taula[i][0] = dia; // allowed, but bad because char is basically a number.
[...]
_taula[i][3] = equipLocal.c_str(); // not allowed, you are assigning a char pointer to a char.
taula[i] is the i-th string in your array. And by putting [0] you assign to the first character in that string. dia is an integer though.
For example
std::string[] = {"Hello", "world", "I", "am", "alive"};
std::cout << string[1] << std::endl; // output "world"
std::cout << string[1][0] << std::endl; // output 'w'
You can not assign a string to a single character.
As a side note, you should look into declaring an enumeration for your array index (and a constant for it's size) to make it more clear and improve maintainability.
What you should probably be doing is create a struct or class for your, whatever it is
struct whateverItIs {
int dia, mes, any, puntsLocal, puntsVisitant;
std::string equipLocal, equipVisitant;
};
Make a new instance of that in your llegir and push it to the back of a std::vector you get by reference.
Just remember to delete() them later especially before that vector goes out of scope.
I have next c++ class called "Contact":
class Contact
{
private:
std::string contactName;
double subscriptionPrice;
int minutesIncluded;
public:
Contact(const std::string &contactName, double subscriptionPrice,
int minutesIncluded) : contactName(contactName), subscriptionPrice(subscriptionPrice), minutesIncluded(minutesIncluded)) {}
Contact() {
}
...gettetrs and setters
}
I have text file with one or more contacts in format:
asd,1.00000,1
In main method I have method that add properly vector of contacts in this text file. Problem is when I try to read from it. My target is to convert text file into vector of contacts. Method I use is next:
void phonebook_load(vector<Contact> &contacts)
{
string line;
ifstream phonebook_file;
vector<std::string> lines;
phonebook_file.open(phonebook_filename);
if(!phonebook_file.is_open())
cout << "Phonebook file could not be openned !!!" << endl;
else
{
while (phonebook_file.good())
{
for (string line; getline(phonebook_file, line, ','); )
lines.push_back(line);
}
phonebook_file.close();
}
}
I have two options:
Read line by line (which I cannot split by ",")
Split by "," which print every property of contact on new line, and I don't see how tho handle it from there.
What should I change in my method in order to read file line by line and properly convert it to vector<Contact>
Provide stream extraction and stream insertion operators for your type:
#include <string>
#include <vector>
#include <iterator>
#include <fstream>
#include <iostream>
class Contact
{
private:
std::string contactName;
double subscriptionPrice;
int minutesIncluded;
public:
Contact() {}
Contact(const std::string &contactName, double subscriptionPrice, int minutesIncluded)
: contactName { contactName },
subscriptionPrice { subscriptionPrice },
minutesIncluded { minutesIncluded }
{}
// declare the stream extraction and stream insertion operators as firends
// of your class to give them direct access to members without the need for
// getter and setter functions.
friend std::istream& operator>>(std::istream &is, Contact &contact);
friend std::ostream& operator<<(std::ostream &os, Contact const &contact);
};
std::istream& operator>>(std::istream &is, Contact &contact)
{
std::string contact_name;
if (!std::getline(is, contact_name, ',')) // use getline with a delimiter
return is; // to allow whitespace in names
// which >> doesn't
char seperator;
double subscription_price;
int minutes_included;
if (!(is >> subscription_price >> seperator >> minutes_included) || seperator != ',') {
is.setstate(std::ios::failbit);
return is;
}
contact = Contact{ contact_name, subscription_price, minutes_included };
return is;
}
std::ostream& operator<<(std::ostream &os, Contact const &contact)
{
os << contact.contactName << ", " << std::fixed << contact.subscriptionPrice
<< ", " << contact.minutesIncluded;
return os;
}
int main()
{
std::ifstream is{ "test.txt" };
std::vector<Contact> contacts{ std::istream_iterator<Contact>{ is },
std::istream_iterator<Contact>{} };
for (auto const &c : contacts)
std::cout << c << '\n';
}
I'm working on boost::asio::streambuf and found out that I can send/get a struct using it, but when I send a struct I just can't get it as I have sent it. The documentation says that one should use commit() and consume(), but where should I use them here?
struct person
{
int m_id;
std::string m_message;
};
std::istream& operator>>(std::istream& in, struct person& p)
{
return in >> p.m_id >> p.m_message;
}
std::ostream& operator<<(std::ostream& out, struct person& p)
{
return out << p.m_id << " " << p.m_message;
}
int main()
{
boost::asio::streambuf buf;
std::ostream out(&buf);
person p;
p.m_id = 1;
p.m_message = "Hello World!";
out << p;
std::istream in(&buf);
person p1;
in >> p1;
cout << "ID: " << p1.m_id << endl;
cout << "Message: " << p1.m_message << endl;
return 0;
}
The problem is with strings so when I type only "hello" (without world), it works fine, but if I add "world!" as shown above it just doesn't see the added "world!", why?
There are a number of issues.
Firstly, make the arguments const& when possible:
std::ostream &operator<<(std::ostream &out, person const &p) {
Secondly, make sure the streams flush to the buffer. I think it's good practice to limit the lifetime of the ostream or istream instances
Thirdly, choose a format that will be robust. Your sample already had bigger problems, when you had m_id = 1 and m_message = "123" (can you see it?).
In text formats you need either fixed-length fields or a delimiting protocol. Let's fix it:
std::ostream &operator<<(std::ostream &out, person const &p) {
return out << p.m_id << ";" << p.m_message.length() << ";" << p.m_message;
}
Now when reading it back you will see how much more precise you need to be:
std::istream &operator>>(std::istream &in, person &p) {
char separator;
size_t length;
bool ok = in >> p.m_id
&& in >> separator && separator == ';'
&& in >> length
&& in >> separator && separator == ';'
;
if (ok) {
p.m_message.resize(length);
in.read(&p.m_message[0], length);
p.m_message.resize(in.gcount());
}
// ensure the expected number of bytes were read
ok = ok && (p.m_message.length() == length);
if (!ok)
in.setstate(std::ios::failbit);
return in;
}
Yikes. Really? Yes really. At a minimum!
Do error handling
Full Demo
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
struct person {
int m_id;
std::string m_message;
};
std::ostream &operator<<(std::ostream &out, person const &p) {
return out << p.m_id << ";" << p.m_message.length() << ";" << p.m_message;
}
std::istream &operator>>(std::istream &in, person &p) {
char separator;
size_t length;
bool ok = in >> p.m_id
&& in >> separator && separator == ';'
&& in >> length
&& in >> separator && separator == ';'
;
if (ok) {
p.m_message.resize(length);
in.read(&p.m_message[0], length);
p.m_message.resize(in.gcount());
}
// ensure the expected number of bytes were read
ok = ok && (p.m_message.length() == length);
if (!ok)
in.setstate(std::ios::failbit);
return in;
}
int main() {
boost::asio::streambuf buf;
std::ostream(&buf) << person{ 1, "Hello World!" };
person received;
if (std::istream(&buf) >> received) {
std::cout << "ID: " << received.m_id << std::endl;
std::cout << "Message: " << received.m_message << std::endl;
} else {
std::cout << "Couldn't receive person\n";
}
}
Prints
ID: 1
Message: Hello World!
BONUS
C++14 added std::quoted:
#include <iomanip>
std::ostream &operator<<(std::ostream &out, person const &p) { return out << p.m_id << std::quoted(p.m_message); }
std::istream &operator>>(std::istream &in, person &p) { return in >> p.m_id >> std::quoted(p.m_message); }
Which, in this case, also does the job: Live On Coliru
From http://en.cppreference.com/w/cpp/string/basic_string/operator_ltltgtgt (emphasis and ellipsis mine):
2) ... reads characters from is and appends them to str ... until one
of the following conditions becomes true:
...
...
std::isspace(c,is.getloc()) is true for the next character c in is (this whitespace character remains in the input stream). ...
Basicaly what this means is that if you extract a string from an istream using operator >> it stops at white spaces.
If you want to get everything from the stream into your string there are plenty of questions asking that (Like this one or this one).
I am having trouble using push_back for vectors in c++.
My vector is named data.
In my loop I want to add 50 to data[i].getQuantity then push_back to data
These are things that I have tried.
data.push_back(data[i].getQuantity());
and
float myFloat = data[i].getQuantity() + 50;
data.push_back(data[i].getQuantity(myFloat));
data.push_back(myFloat);
The error is saying
No function to call to push_back
Here is my code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
struct Input
{
friend std::istream& operator >>(std::istream& inp, Input& item);
friend std::ostream& operator <<(std::ostream& outp, Input const& item);
std::string group;
std::string total_pay;
float quantity;
// default constructor. sets up zero-elements
Input() : group(), total_pay(), quantity()
{
}
Input(std::string groupIn, std::string total_payIn, float quantityIn) :
group(std::move(groupIn)),
total_pay(total_payIn),
quantity(quantityIn)
{
}
// Accessors
std::string const& getGroup() const { return group; }
std::string getTotalPay() const { return total_pay; }
float getQuantity() const { return quantity; }
};
// global free function for extracting an Input item from an input stream
std::istream& operator >>(std::istream& inp, Input& item)
{
return (inp >> item.group >> item.total_pay >> item.quantity);
}
// global operator for inserting to a stream
std::ostream& operator <<(std::ostream& outp, Input const& item)
{
outp
<< item.getGroup() << ", "
<< item.getTotalPay() << ", "
<< item.getQuantity();
return outp;
}
struct ctype : std::ctype<char>
{
static mask* make_table()
{
static std::vector<mask> table(classic_table(),
classic_table() + table_size);
table[','] |= space;
return &table[0];
}
ctype() : std::ctype<char>(make_table()) { }
};
int main() {
std::fstream infile("employee.dat");
std::vector<Input> data;
std::string line;
try {
while (std::getline(infile, line))
{
std::istringstream iss(line);
Input inp;
iss.imbue(std::locale(iss.getloc(), new ctype));
while (iss >> inp) // calls our extraction operator >>
data.push_back(inp);
if (iss.fail() && !iss.eof())
std::cerr << "Invalid input line: " << line << '\n';
}
// dump all of them to stdout. calls our insertion operator <<
std::copy(data.begin(), data.end(),
std::ostream_iterator<Input>(std::cout,"\n"));
std::ofstream outp("output.dat");
for(int i = 0; i < data[i].getQuantity(); i++)
{
float myFloat = data[i].getQuantity() + 50;
data.push_back(myFloat);
outp << data[i].getGroup() << ',' << data[i].getTotalPay() << ',' << data[i].getQuantity() + 50 << '\n';
}
} catch (std::exception& e) {
std::cout << "There was an error: " << '\n';
return 1;
}
return 0;
}
Your vector is of type std::vector<Input>. That means you can only put objects of type Input into it. You can't push_back a float into such a vector.
If your intention is to create a new Input object and push that back into your vector, you could do something like
data.push_back(Input(data[i].getGroup(), data[i].getTotalPay(), data[i].getQuantity() + 50))
On the other hand, if you are simply trying to modify an element in data without adding a new element to data, you could just do
data[i].quantity += 50;
This works because you use a struct rather than a class. In a struct, variables default privacy level is public. If you wanted to use a class, or you just don't want to directly access the struct members, you would have to create a setter function for quantity.
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.