I am in the process of learning c++ and have a question regarding reading and writing objects to files.
I created a class called Person. In my main file I created two instances of the Person class. I write instance one to a file called "person.dat" and later read it back into the second instance I created. Everything is working as expected except that there is an exception that is thrown after the program closes. I am not sure why or what is causing it.
Exception: Unhandled exception at 0x55ABDF62 (msvcp120d.dll) in
Writing Binary Objects.exe: 0xC0000005: Access violation writing
location 0xFEEEFEEE.
Can anybody shed some light on this for me?
Code: Person.h
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string name;
string surname;
int age;
public:
Person();
Person(string, string, int);
void setName(string);
void setSurname(string);
void setAge(int);
string getName();
string getSurname();
int getAge();
};
Person::Person() {}
Person::Person(string _name, string _surname, int _age) {
setName(_name);
setSurname(_surname);
setAge(_age);
}
void Person::setName(string _name) {
name = _name;
}
void Person::setSurname(string _surname) {
surname = _surname;
}
void Person::setAge(int _age) {
age = _age;
}
string Person::getName() {
return name;
}
string Person::getSurname() {
return surname;
}
int Person::getAge() {
return age;
}
Code: Program.cpp
#include <iostream>
#include <fstream>
#include "Person.h"
using namespace std;
int main() {
//create person 1
Person person;
person.setName("Kobus");
person.setSurname("Beets");
person.setAge(24);
//write person 1 to file
ofstream out;
out.open("person.dat", ios::binary);
out.write(reinterpret_cast <char *> (&person), sizeof(person));
out.close();
//create person 2
Person person2;
person2.setName("John");
person2.setSurname("Doe");
person2.setAge(26);
//read person 1 from file into person 2
ifstream in;
in.open("person.dat", ios::binary);
in.read(reinterpret_cast <char *> (&person2), sizeof(person2));
in.close();
//print new person 2
cout << " " << person2.getName() << " " << person2.getSurname() << " is " << person2.getAge() << " year(s) old... \n\n ";
system("pause");
return 0;
}
You cannot directly write objects to a file in this way, unless you have a POD-style data structures (e.g. just simple C data types or a struct/class thereof, no pointers, no C++ data types).
In your case, Person has two std::string members, which itself contain pointers and other stuff, which will loose its meaning once written to file and re-read to memory.
You would need to add some more logic to write the actual string contents (see std::string::c_str(), std::string::data(), std::string::size()).
The exception is probably causes by the std::string desctructor, which tries to free or access memory which is already freed.
Related
I am trying to create a class object s2 with some customized attributes and some attributes from default constructor however my output is the wrong output for the get_year function. It should be outputing 0 which is the key for FRESHMAN but it is out putting 2 instead. The rest of the code is outputting as expected:
#include <stdio.h>
#include <iostream>
#include <algorithm> // for std::find
#include <iterator> // for std::begin, std::end
#include <ctime>
#include <vector>
#include <cctype>
using namespace std;
enum year {FRESHMAN, SOPHOMORE, JUNIOR, SENIOR};
struct name
{
string firstName;
string lastName;
friend std::ostream& operator <<(ostream& os, const name& input)
{
os << input.firstName << ' ' << input.lastName << '\n';
return os;
}
};
class Student: name{
private:
name Name;
year Year;
int idNumber;
string Department;
public:
void setname(string fn="", string ln="")
{
Name.firstName =fn;
Name.lastName =ln;
}
name get_name()
{
return Name;
}
void set_year(year yr=FRESHMAN)
{
Year=yr;
}
year get_year()
{
return Year;
}
void set_ID(int ID=0)
{
idNumber=ID;
}
int get_ID()
{
return idNumber;
}
void set_Department(string Dept="")
{
Department=Dept;
}
string get_Department()
{
return Department;
}
};
int main()
{
Student s2;
s2.setname("Nikolai", "Khabeboolin");
s2.set_ID(12436193);
cout<<"ID is: "<< s2.get_ID()<<", name is "<< s2.get_name()<<", year in school is: "<<s2.get_year()<<", Department is "<<s2.get_Department()<<endl;
return 0;
}
Student lacks a constructor, so all its members are default initialized, and the default initialization of year Year and int idNumber is "no initialization", so reading from them is undefined behavior. Reading them might find 0, 2, a random value each time, or crash.
I see that your class contains a void set_year(year yr=FRESHMAN) member, but your code never called set_year, so no part of this executed.
You should make a default constructor for Student, or as Goswin von Brederlow stated, use year Year{FRESHMAN}; and int idNumber{-1}; when declaring the members, to give them default initializations.
By not explicitly declaring and defining a constructor, in this case Student(), you open yourself up to undefined behavior. Your constructor should call set_year(year yr=FRESHMAN) OR even better, just set the year itself.
I have a issue about my constructor is not correctly working. Whenever i run the program, my overloaded operator might not be perform correctly because i always get the default constructor values when i get the output with cout.
I believe that i made my constructor declarations well but all of my objects getting filled with 0 and Unknown
here is my txt file:
1 Prince Heins 25
2 Lady Bridgette 29
3 Tony Ann 223
4 Lucy Phoenix 35
Here is my code;
#include <iostream>
#include <string>
#include <conio.h>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <istream>
#include <iomanip>
#include <cstring>
#include <ostream>
using namespace std;
class contact{
private:
int listno;
string name;
string surname;
string phonenumber;
public:
contact(){
this->name="Unknown";
this->surname="Unknown";
this->phonenumber="Unknown";
this->listno=0;
}
contact (string name,string surname,string phonenumber){
this->name=name;
this->surname=surname;
this->phonenumber=phonenumber;
}
contact(int listno,string name,string surname,string phonenumber){
this->name=name;
this->surname=surname;
this->listno=listno;
this->phonenumber=phonenumber;
}
friend ostream & operator<< (ostream &out, const contact &con){
out << con.listno << con.name << con.surname << con.phonenumber;
return out;
}
friend istream & operator>> (istream &in, contact &con){
in >> con.listno >> con.name >> con.surname >> con.phonenumber;
return in;
}
};
int main(){
ifstream pbin("phoneData2.txt");
string line;
long linecount;
for(linecount=0;getline(pbin,line);linecount++);
contact* myArray = new contact[linecount];
pbin.seekg(0);
if(pbin.is_open()){
int i;
for(i=0;i<linecount;i++){
if(pbin!=NULL){
while(pbin>>myArray[i]);
}
}
pbin.close();
cout << myArray[2]; // try attempt
return 0;
}
}
and here is my output for cout << Array[2];
OutputArray2
The problem results from the wrong used algorithm and wrongly placed statements.
So, let's look what is going on in the below:
long linecount;
for(linecount=0;getline(pbin,line);linecount++)
;
contact* myArray = new contact[linecount];
pbin.seekg(0);
if(pbin.is_open()){
int i;
for(i=0;i<linecount;i++){
if(pbin!=NULL) {
while(pbin>>myArray[i]);
}
}
pbin.close();
You want to count the lines. So you read all lines until the eofstate is set. But, additionally, also the fail bit will be set. See also here.
If you use your debugger, you will find a 3 in _Mystate.
Then you perform a seekg. This will reset the eof bit but keep the fail bit. The dubugger shows then
You can see that the fail bit is still set.
So, and this will now lead to the main problem. If your write if(pbin!=NULL) which is definitely wrong (on my machine is does not even compile), or if you better write if(pbin) the fail bit will still be set. And because the bool and the ! operator for streams is overwritten (please see here) the result of the if and while will be false and your pbin>>myArray[i] will never be executed.
So, a pbin.clear() would help.
But, although your class definition is already very good, with inserter and extractor overwritten, you do not use the full C++ power for reading the data.
One basic recommendation would be to never use raw pointers for owned memory. And best also not new. Use dedicated containers for your purpose. E.g. a std::vector. The you can use the std::vectors constructor no 5 together with a std::istream_iterator. Please read here. The range based constructor for the std::vector will copy data from a given range, denoted by the begin and end iterator. And if you use the std::istream_iterator, it will call your overwritten extractor operator, until all data are read.
So your main shrinks to:
int main() {
// Open source file and check, if it could be opened
if (ifstream pbin("r:\\phoneData2.txt");pbin) {
// Read complete source file
std::vector data(std::istream_iterator<contact>(pbin), {});
// Show data on console
std::copy(data.begin(), data.end(), std::ostream_iterator<contact>(std::cout, "\n"));
}
return 0;
}
This looks by far compacter and is easier to read. We start with an if-statement with initializer. The initializer parts defines the variable and the constructor will open the file for us. In the condition part, we simple write pbin. And, as explained above, its bool operator will be called, to check if everything was ok.
Please note:
We do not need a close statement, because the destructor of the
std::ifstream will close the file for us.
The outer namespace will not be polluted with the variable name pbin. That is one of the reasons, why ifstatement with initializer should be used.
We alread descibed the std::vector with its range constructor. SO reading the complete file is simple done by the very simple statement
std::vector data(std::istream_iterator<contact>(pbin), {});
Please note:
We do not define the type of the std::vector. This will be automatically deduced by the compiler through CTAD
We use the default initialzer {} for the end iterator, as can be seen here in constructor number 1.
The whole program could then be rewritten to:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
class contact {
private:
int listno;
string name;
string surname;
string phonenumber;
public:
contact() {
this->name = "Unknown";
this->surname = "Unknown";
this->phonenumber = "Unknown";
this->listno = 0;
}
contact(string name, string surname, string phonenumber) {
this->name = name;
this->surname = surname;
this->phonenumber = phonenumber;
}
contact(int listno, string name, string surname, string phonenumber) {
this->name = name;
this->surname = surname;
this->listno = listno;
this->phonenumber = phonenumber;
}
friend ostream& operator<< (ostream& out, const contact& con) {
out << con.listno << '\t' << con.name << '\t' << con.surname << '\t' << con.phonenumber;
return out;
}
friend istream& operator>> (istream& in, contact& con) {
in >> con.listno >> con.name >> con.surname >> con.phonenumber;
return in;
}
};
int main() {
// Open source file and check, if it could be opened
if (ifstream pbin("r:\\phoneData2.txt");pbin) {
// Read complete source file
std::vector data(std::istream_iterator<contact>(pbin), {});
// Show data on console
std::copy(data.begin(), data.end(), std::ostream_iterator<contact>(std::cout, "\n"));
}
return 0;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I want to create a Student object in C++ and it has the properties of name, major, age and id. The object initialization will be done in the main() part and Student object has the get and set methods for all the constructors. I want to print the student objects in the main() part but I get this error:
in C++98 's1' must be initialized by constructor, not by '{...}'
I am using GNU GCC Complier in Codeblocks. I haven't written specifically any code for compiling or debugging.
I tried to initialize the objects by assigning them to this, making them null, giving them zero and random values but they haven't worked.
Student.h file
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
string name, major;
int age, id;
Student(string name, string major, int age, int id);
string getName();
void setName(string name);
string getMajor();
void setMajor(string major);
int getAge();
void setAge(int age);
int getId();
void setId(int id);
};
ostream & operator << (ostream &out, Student &s);
#endif // STUDENT_H
Student.cpp file
#include "Student.h"
#include <iostream>
using namespace std;
Student::Student(string newName, string newMajor, int newAge, int newId)
{
name = newName;
major = newMajor;
age = newAge;
id = newId;
}
string Student::getName(){
return name;
}
void Student::setName(string newName){
name = newName;
}
string Student::getMajor(){
return major;
}
void Student::setMajor(string newMajor){
major = newMajor;
}
int Student::getAge(){
return age;
}
void Student::setAge(int newAge){
age = newAge;
}
int Student::getId(){
return id;
}
void Student::setId(int newId){
id = newId;
}
ostream & operator << (ostream &out, Student &s)
{
out << "Name: " << s.getName() << " Major: " << s.getMajor() << " Age: " << s.getAge() << " Id:" << s.getId() << endl;
return out;
}
Main.cpp file
#include <iostream>
#include <string>
#include "Student.h"
using namespace std;
int main()
{
Student s1 {"John","MATH",24,123456};
Student s2 {"Steve","ENG",22,654321};
cout << s1 << endl;
cout << s2 << endl;
return 0;
}
I expect to print out the properties of the students as a list but when I run it the program crashes and I get this error:
** in C++98 's1' must be initialized by constructor, not by '{...}' **
I fixed my problem. There were a few problems so here I will explain my solutions in detail.
1-My code is written in C++11 syntax but I was using C++98 syntax so I changed my complier to C++11.
2-My initialization was wrong, I used new variables such as newName, newAge... to change the properties of the Student object.
3-My set methods were wrong so I changed them similar to my initialization.
4-I added an opeator to print out properties more easily.
All the changes are updated for the code in the question
I'm currently defining a few properties for a class in C++ but I'm running into trouble when using type string as opposed to something like int or double. For example:
private:
int LOT;
public:
int getLOT() {
return LOT;
}
void setLOT(int value) {
LOT = value;
}
works fine, but:
private:
string name;
public:
string getName() {
return name;
}
void setName(string value) {
name = value;
}
throws these errors:
https://s26.postimg.org/wm5y7922h/error.png
The file (a header) looks something like this:
#include "general.h" // a header which includes all my other #includes
// which, yes, does include <string>
class MyClass
{
private:
string name;
public:
string getName() {
return name;
}
void setName(string value) {
name = value;
}
// other properties similar to the above
}
The purpose is to access the variable like this:
cout << "Enter your name: ";
cin >> MyClass.setName();
cout << "\nHello, " << MyClass.getName();
// although this isn't exactly how it'll be used in-program
If anyone could provide help with what I'm doing wrong or a better way to go about a string property (as, like I mentioned before, other types work fine) it would be greatly appreciated. Thanks.
string is part of std namespace.
You must use std::string instead of string or add using namespace std; (what I would not recommend you to do in your header file, read "using namespace" in c++ headers).
I have just learnt some object oriented programming concepts in Python, but I want to transfer this knowledge to C++, and I have trouble with basic implementation that used to be easy using Python.
#include<iostream>
using namespace std;
class Animal{
char name;
int age;
public:
Animal(char name, int age);
};
Animal::Animal(char name, int age) {
this->name = name;
this->age = age;
}
int main()
{
Animal dog ("Megg", 10);
cout << "Name: " dog.name <<endl;
return 0;
}
When I compile this code, I get a lot of messages, such as:
error: no matching function for call to 'Animal::Animal(const char[5], int)'
note: Animal::Animal(char, int) <near match>
note: candidate expects 1 argument, 2 provided
Thanks!
you don't need to do this->name = name in your constructor definition
"Megg" is a string literal. You can cast "Megg" into const char * but not into a char (this was most likely causing your error).
or better yet. You can use the C++ Standard Library string class std::string
#include <iostream>
#include <string>
class Animal{
std::string name;
int age;
public:
Animal(std::string name, int age);
std::string getName() const;
int getAge() const;
};
Animal::Animal(std::string Name, int Age) {
name = Name;
age = Age;
}
std::string Animal::getName() const {
return name;
}
int Animal::getAge() const {
return age;
}
int main()
{
Animal dog ("Megg", 10);
std::cout << "Name: " << dog.getName() << std::endl; // Error in this line. Missing << between "Name: " and dog.name
return 0;
}
Some additional edits:
You should avoid using using namespace std as it takes everything in the Standard Library (from the files you've included) and puts it in the global namespace. You can instead use the scope resolution operator :: as seen above.
When you start working with multiple libraries you may encounter that both have a class named vector or string, or functions with the same name. The way to avoid this is to specify what namespace you want to use.
or alteratively you can do the following:
using std::cout;
using std::endl;
using std::string;
Additionaly in order for you program to work you need a way to access your object's member variables. You could do this by making the variables public or the better practice is to add accessor functions.