I'm trying to use fstream to write an object to a file and read it after but when I try to show the object read on the screen using cout the error message Segmentation fault: 11 appears. Someone could help me with this code? Thanks in advance!
Produto *p1 = new Produto(1, "Refrigerante");
cout << "Produto p1 (pre serializacao): (" << p1->codigo << ") " << p1->descricao << endl;
ofstream serializationWriter;
serializationWriter.open("myobject.dat", ios::binary);
serializationWriter.write((char *)&p1, sizeof(p1));
Produto *p2;
ifstream serializationReader;
serializationReader.open("myobject.dat", ios::binary);
serializationReader.read((char *)&p2, sizeof(p2));
cout << "Produto p2 (pos serializacao): (" << p2->codigo << ") " << p2->descricao << endl;
You need provide some serialization mechanism for class Produto. For example:
class Produto {
// ...
private:
std::string m_str;
private:
friend ostream& operator<<(ostream& stream, const Produto& obj);
friend istream& operator>>(istream& stream, Prodoto& obj)
};
ostream& operator<<(ostream& stream, const Produto& obj)
{
// Write all data to stream.
// ...
stream << obj.m_str;
return stream;
}
istream& operator>>(istream& stream, Prodoto& obj)
{
// Read all data from strem.
// ...
stream >> obj.m_str;
return stream;
}
And then use it as below:
Produto p1(1, "Refrigerante");
ofstream serializationWriter;
// ...
serializationWriter << p1;
Produto p2;
ifstream serializationReader;
// ...
serializationReader >> p2;
For more details see overload ostream istream operator
Related
Here I'm trying to overwrite the inventory objects, but when I run the second std::cout it print the old value again, I want it to write the inputted value.
#include <iostream>
#include <string>
class inventory
{
private:
std::string item;
int onhand;
double cost;
public:
inventory(std::string i, int o, double c){
item = i;
onhand = o;
cost = c;
}
friend std::ostream& operator<<(std::ostream& stream, inventory entity){
stream << entity.item << "\t" << entity.onhand << "\t" << entity.cost << std::endl;
return stream;
}
friend std::istream& operator>>(std::istream& stream, inventory entity){
stream >> entity.item >> entity.onhand >> entity.cost;
return stream;
}
};
int main()
{
inventory obj("hammer", 12, 2000);
std::cout << obj;
std::cin >> obj;
std::cout << obj;
return 0;
}
The problem you're facing is, that you pass your inventory obj by value
What you want is passing it as reference like so:
friend std::istream& operator>>(std::istream& stream, inventory &entity)
Your operator>> accepts a copy of object and modifies that copy. You need to pass by reference:
friend std::istream& operator>>(std::istream& stream, inventory entity);
I am reading a structure named "Highscore" from a binary file. I print the read data in the console and it looks fine. After that, I insert them into a vector with the push_back method and when I'm done, I return the vector.
After the return line, I get the following error (translated from French):
"Exception not handled at 0x00007FF6223FF017 in Project1.exe : 0xC0000005 : access violation while reading from 0xFFFFFFFFFFFFFFFF.".
Here is my code:
struct Highscore{
string username;
int points;
};
vector<Highscore> ReadFromHighscores(){
fstream highscoresFiles;
highscoresFiles.open("highscores.db", ios::in | ios::out | ios::binary | ios::app);
highscoresFiles.seekg(0);
Highscore output;
vector<Highscore> highscores;
highscoresFiles.read(reinterpret_cast<char *>(&output), sizeof(Highscore));
cout << "Read : " << output.points << output.username << endl;
Highscore temp;
temp.points = output.points;
temp.username = output.username;
if (!highscoresFiles.eof()) {
highscores.push_back(temp);
}
highscoresFiles.close();
return highscores;
}
As having been pointed out, std::string contains a char* (which you are saving and restoring) to the real data. The actual data is not saved and the pointer you restore is causing the crash. To fix that you can create operators for streaming to/from files and dump the username c-string (including the terminating \0) and then write the points int raw. This should work as long as your usernames don't contain \0 in the middle of the string (unusual but valid).
#include <iostream>
#include <iomanip>
#include <vector>
#include <fstream>
struct Highscore{
std::string username;
int points;
Highscore(const std::string& n, int p) : username(n), points(p) {}
Highscore() : Highscore("",0) {}
// operator to save a Highscore to file
friend std::ofstream& operator<<(std::ofstream&, const Highscore&);
// operator to read a Highscore from file
friend std::ifstream& operator>>(std::ifstream&, Highscore&);
// operator to print a Highscore on other ostreams (like std::cout)
friend std::ostream& operator<<(std::ostream&, const Highscore&);
};
std::ofstream& operator<<(std::ofstream& os, const Highscore& hs) {
os.write(hs.username.c_str(), hs.username.size()+1);
os.write(reinterpret_cast<const char*>(&hs.points), sizeof(hs.points));
return os;
}
std::ifstream& operator>>(std::ifstream& is, Highscore& hs) {
std::getline(is, hs.username, '\0');
is.read(reinterpret_cast<char*>(&hs.points), sizeof(hs.points));
return is;
}
std::ostream& operator<<(std::ostream& os, const Highscore& hs) {
os << std::setw(15) << std::left << hs.username << std::setw(8) << std::right << hs.points;
return os;
}
int main() {
// create "highscores.db"
{
std::vector<Highscore> highscores {
{"MadBrother33", 234234},
{"Barny", 14234},
{"Bart", 1434}
};
std::ofstream out("highscores.db", std::ios::binary);
for(auto& hs : highscores) {
out << hs;
}
}
// read "highscores.db"
{
std::vector<Highscore> highscores;
{
Highscore hs;
std::ifstream in("highscores.db", std::ios::binary);
while(in>>hs) {
highscores.emplace_back(std::move(hs));
}
}
for(auto& hs : highscores) {
std::cout << hs << "\n";
}
}
}
Output
MadBrother33 234234
Barny 14234
Bart 1434
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 trying to write a program where you register a bank account and modify it. This is the code (Not full but just trying to experiment with file handling; I am a beginner at programming)
#include <iostream>
#include <fstream>
#include <string>
std::ofstream outfile;
std::ifstream infile;
std::fstream inout;
struct bank{
int acc_nr;
std::string emri;
std::string mbiemri;
};
std::istream& operator>> (std::ifstream& in, bank& klient)
{
in >> klient.emri;
in >> klient.mbiemri;
in >> klient.acc_nr;
return in;
}
std::ostream& operator<< (std::ofstream& out, bank& klient)
{
out << klient.emri << std::endl;;
out << klient.mbiemri << std::endl;
out << klient.acc_nr << std::endl;
return out;
}
std::ostream& operator<< (std::fstream& out, bank& klient)
{
out << klient.emri << std::endl;;
out << klient.mbiemri << std::endl;
out << klient.acc_nr<< std::endl;
return out;
}
std::istream& operator>> (std::fstream& in, bank& klient)
{
in >> klient.emri;
in >> klient.mbiemri;
in >> klient.acc_nr;
return in;
}
std::istream &read(bank &klient, std::istream &is)
{
std::cout << "Jepni emrin: ";
is >> klient.emri;
std::cout << "Jepni mbiemrin: ";
is >> klient.mbiemri;
std::cout << "Jep numrin e akaundit: ";
is >> klient.acc_nr;
return is;
}
const std::ostream &print(bank klient, std::ostream &os)
{
std::cout << "Emri: ";
os << klient.emri;
std::cout << "\nMbiemri: ";
os << klient.mbiemri;
std::cout << "\nNumri i akaundit: ";
os << klient.acc_nr;
return os;
}
void read_infile(bank &klient)
{
read(klient, std::cin);
outfile.open("C:\\publik\\sample.dat", std::ios::app| std::ios::binary);
outfile.write(reinterpret_cast <char *>(&klient), sizeof(bank));
outfile.close();
}
void print_outfile(bank klient)
{
infile.open("C:\\publik\\sample.dat", std::ios::in| std::ios::binary);
infile.read(reinterpret_cast <char *>(&klient), sizeof(bank));
infile.close();
}
void kerko(std::string emri, std::streampos& a)
{
bank temp;
inout.open("C:\\publik\\sample.dat", std::ios::in | std::ios::out | std::ios::binary);
while (inout.read(reinterpret_cast <char *>(&temp), sizeof(bank)))
{
if (emri == temp.emri) // emri = name.
{
print(temp, std::cout);
a = inout.tellg();
inout.close();
break;
}
}
}
int main()
{
bank klient;
bank temp2;
std::string emri;
std::streampos a;
std::cin >> emri;
bank temp;
kerko(emri,a);
std::cout <<std::endl;
system("pause");
return 0;
}
The code reads a name, searches through the file and then displays its information. The searching and displaying are successful but I get this error
Unhandled exception at 0x77CFDF58 (msvcp120d.dll) in Banke.exe:
0xC0000005: Access violation reading location 0x00DCAB9C.
The code does not execute past the print function call in the while loop.
Thank you for your time.
There are several things that are wrong here.
First of all you cannot do this:
read(klient, std::cin);
outfile.open("C:\\publik\\sample.dat", std::ios::app| std::ios::binary);
outfile.write(reinterpret_cast <char *>(&klient), sizeof(bank));
your &klient is a complex structure, using a type (std::string) of which you know nothing about its internal layout. It may have pointers pointing 'outside' of it. To read a record you should so something like this;
bank klient ;
std::ifstream istream("name", std::ios::app| std::ios::binary); // or use open
istream >> klient ;
And here we get to second point. This definition is quite ok (I would have used std::ostream instead of std::ofstream but that's a minor point)
std::ostream& operator<< (std::ofstream& out, bank& klient)
{
out << klient.emri << std::endl;;
out << klient.mbiemri << std::endl;
out << klient.acc_nr << std::endl;
return out;
}
The main point is that when you want to read emri or mbiemri how do you know where the first ends, and the second starts? The simplest way could be insert a space. It works only if emri/mbiemri do not contain spaces themselves, but for a beginner could be a good starting point.
And that's all for now, you have enough to think about...
I'm currently trying to copy a vector to a new text file after making the necessary changes to the vector. I can build the project fine, but its giving me weird errors that I don't understand. Could anyone possibly help me with this?
My struct
class AccDetails {
public:
string username;
string name;
string topicid;
string testid;
};
The code that is giving me the errors
vector<AccDetails>accInfo;
ofstream temp ("temp.txt");
ostream_iterator<AccDetails>temp_itr(temp,"\n");
copy(accInfo.begin(),accInfo.end(),temp_itr);
There's a whole chunk of error lines, but i think this should be the important 2 lines:
You'll need to overload operator<< for AccDetails. It is what ostream_iterator calls internaly.
Something like this:
std::ostream& operator<<(std::ostream& stream, const AccDetails& obj)
{
// insert objects fields in the stream one by one along with some
// description and formatting:
stream << "User Name: " << obj.username << '\n'
<< "Real Name: " << obj.name << '\n'
<< obj.topicid << ' ' << obj.testid << '\n';
return stream;
}
The operator takes the stream it inserts to as first parameter and a constant reference to the object it is streaming as the second one (this allows passing temporary AccDetails, too). Now you can also say:
AccDetails acc;
std::cout << acc;
If the operator would need access to AccDetail's private fields, you would need to declare as a friend.
If you're new to operator overloading, I suggest you read this SO thread.
Hope that helps.
Can have this after overloading as jrok said:
class AccDetails
{
std::string username;
std::string name;
std::string topicid;
std::string testid;
friend std::ostream& operator<<(std::ostream&, const AccDetails&);
friend std::istream& operator>>(std::istream& is, AccDetails& );
};
std::ostream& operator<<(std::ostream& os, const AccDetails& acc)
{
os << "User Name: " << acc.username << std::endl
<< "Name: " << acc.name << std::endl
<< acc.topicid << ' ' << acc.testid << std::endl;
return os;
}
std::istream& operator>>(std::istream& is, AccDetails& acc)
{
is >> acc.username >>acc.name >> acc.topicid >> acc.testid ;
return is;
}
int main()
{
std::vector<AccDetails>accInfo;
std::copy(std::istream_iterator<AccDetails>(std::cin),
std::istream_iterator<AccDetails>(),std::back_inserter(accInfo) );
std::ofstream temp("temp.txt",std::ios::out);
std::ostream_iterator<AccDetails>temp_itr(temp,"\n");
std::copy(accInfo.begin(),accInfo.end(),temp_itr);
}