C++ Program crashes when reading object from random access file - c++

I have the following User.h that holds several attributes (strings). User.cpp has all the definitions.
//User.h
#ifndef USER_H
#define USER_H
#include<iostream>
#include <cstring>
using namespace std;
class User{
string username;
public:
User();
string getUsername() const;
void setUsername(string);
};
#endif
I'm using a another class, "File" to insert new users/view users from a randomly accessed .dat file
//File.h
#ifndef FILE_H
#define FILE_H
#include "User.h"
class File{
public:
void loadUser();
bool addUser(User&);
};
#endif
File class definitions
//File.cpp
#include<cstring>
#include<iostream>
#include<iomanip>
#include<fstream>
#include "User.h"
#include "File.h"
using namespace std;
User tempUser;
fstream usersFile;
void File::loadUser(){
usersFile.open("users.dat", ios::in | ios::binary);
usersFile.seekg(0);
// commenting the following lines prevented the issue
usersFile.read(reinterpret_cast<char *>(&tempUser), sizeof(tempUser));
cout<<tempUser.getUsername().c_str();
usersFile.close();
}
bool File::addUser(User& user){
usersFile.open("users.dat", ios::out | ios::ate | ios::binary);
// no issue when writing to file
usersFile.write( reinterpret_cast<const char *>(&user), sizeof(user));
usersFile.close();
cout<<"User added";
}
I'm getting the above mentioned issue when running. No compilation issue though.
Is there any issue when dealing with objects that has "string attributes" inside, in handling?
Please help

I think the issue is that you are mixing C++ code with a C mindset.
What you should really be doing here is use the extraction operator, opeartor>>(), along with the C++ IO streams. This, as opposed to using the C standard IO along with the read() function. For writing an object, use the insertion operator operator<<() instead of the C write() function.
For working with strings use std::string. This class provides operator<<() and operator>>(). So, you can say std::string s and then io << s and io >> s where io is some C++ IO stream object. This will do The Right Thing(tm). The philosophy here is that the std::string class knows better than you, a user, how to serialize a std::string object. So let it do it, with the << and >> operators.
Going on with the idea, you, as the author of User, know better than anyone else how to serialize a User object. So provide the << and >> operators for users of your class, as a service. "Users of your class" might well be you one week from now, when you have completely forgot how to properly serialize a User object. (Or, you think you remember but in practice you forgot a detail, causing a bug in your code). Example:
// in User.h
#include <string>
#include <iosfwd> // forward declarations of standard IO streams
namespace mine {
class User {
User(const std::string& name) : username(name) { }
friend std::ostream& operator<<(std::ostream&, const User&);
friend std::istream& operator>>(std::istream&, User&);
private:
std::string username;
};
std::ostream& operator<<(std::ostream& out, const User& u)
{
return out << u.username;
}
std::istream& operator>>(std::istream& in, User& u)
{
return in >> u.username;
}
} // namespace mine
From here on, to save a user to a file you say
std::ofstream f("filename");
User u("John");
f << u;
That's it. To read a user:
std::ifstream f2("filename");
f2 >> u;
It's a good practice to wrap your code in a namespace. IDEs give a good visualization of this issue, by showing how many symbols are visible with the auto-complete feature. You get to see how much of a mess there is in the global scope. By wrapping your code in a namespace you group it under a scope name, saving some more mess in the global name scope. It's just about being tidy. If you put your code in your own namespace then you can choose any name you want for a function, a class or a variable, so long as you haven't chosen it before. If you don't put it in a namespace then you need to share names with others. It's like a skunk declaring his own territory, only without the bed smell.
On that note I suggest you take off that using namespace std from your header. This brings all the symbols in the std namespace into scope of all files that #include the header. It's a bad practice. Only say using namespace std in implementation files, if you wish, but not in header files.
Granted, some will say even this is a bad idea. I personally think it's fine if you're aware of the fact you might have name clashes in that particular implementation file. But at least you know where that using statement is: it's in your implementation file, and it only causes clashes in that implementation file. It's sort of a gun, (a plastic water gun, but a gun nonetheless), only you can only shoot (wet) your own feet and no one else's. Which in my opinion is perfectly fine.

You can't read non-POD types like that. A string is not a POD type.
What are POD types in C++?
There are a few ways to read in strings properly, depending upon how they were stored.
For text files:
If the string is just a single word, separated on both sides by whitespace, you can use the plain old >> operator. If it's more than one word, you can store it on it's own line, and use getline.
For binary files:
Store the string in null terminated form. Read it one character at a time, checking for the null character. Or, prepend the string with an integer storing it's size. When you read it, first read in the integer, then read in that many characters.

string is an object, which means you're not writing it's contents.
Try writing an User and examine the file to see what I mean. What you're then reading are some pointers, that point to invalid memory locations.

Yes, the std::string class is not plain old data, in other words it contains pointers.
If you save/load the string class in this manner, the data pointed to won't be loaded/saved, only the value of the pointer.
Additionally sizeof(tempUser) won't include the size of the text pointed to by the strings.
Your solution is to change how you're reading/writing data.
One way is to use boost::serialization which handles datatypes like std::string.
Another way would be to write each string to a separate line in the text document yourself (not in binary mode) and then use readline to read them back in.

Rather than construct your own custom serialization code, something like Google Protocol Buffers might do what you want with less effort. It's ideal for passing around simple structured data from place to place.

Related

Moving std::istream

I have a Scanner class to tokenize streams of characters coming from files, cin, etc.
class Scanner {
public:
Scanner(std::istream&& c) : input{std::move(c)} {}
private:
std::istream input;
};
This code does not compile because the move constructor of std::istream is protected. I could use a reference to the stream instead, but then, I have no guarantee that someone is not playing with my stream outside of the Scanner class (ss below).
std::string code = "this is code";
std::stringstream ss{code};
Scanner scanner{ss};
Is there a neat way to address this issue, or do people just use std::istream& and hope for the best?
From what I can remember about my work with stream objects.
You need to think about this a bit differently.
class Scanner {
public:
Scanner() {}
virtual void scan(std::istream & p_stream);
};
Your Scanner class could just be focused on scanning the input for whatever, not actually containing it.
Now it can be focused purely on a single task.
Then you need to work out what is the best way for you to keep the stream object alive. I suggest a separate class for that task.
I would have written this as a comment, but there's too much here.

C++ file read error in Debug mode in Visual C++ [duplicate]

I have the following User.h that holds several attributes (strings). User.cpp has all the definitions.
//User.h
#ifndef USER_H
#define USER_H
#include<iostream>
#include <cstring>
using namespace std;
class User{
string username;
public:
User();
string getUsername() const;
void setUsername(string);
};
#endif
I'm using a another class, "File" to insert new users/view users from a randomly accessed .dat file
//File.h
#ifndef FILE_H
#define FILE_H
#include "User.h"
class File{
public:
void loadUser();
bool addUser(User&);
};
#endif
File class definitions
//File.cpp
#include<cstring>
#include<iostream>
#include<iomanip>
#include<fstream>
#include "User.h"
#include "File.h"
using namespace std;
User tempUser;
fstream usersFile;
void File::loadUser(){
usersFile.open("users.dat", ios::in | ios::binary);
usersFile.seekg(0);
// commenting the following lines prevented the issue
usersFile.read(reinterpret_cast<char *>(&tempUser), sizeof(tempUser));
cout<<tempUser.getUsername().c_str();
usersFile.close();
}
bool File::addUser(User& user){
usersFile.open("users.dat", ios::out | ios::ate | ios::binary);
// no issue when writing to file
usersFile.write( reinterpret_cast<const char *>(&user), sizeof(user));
usersFile.close();
cout<<"User added";
}
I'm getting the above mentioned issue when running. No compilation issue though.
Is there any issue when dealing with objects that has "string attributes" inside, in handling?
Please help
I think the issue is that you are mixing C++ code with a C mindset.
What you should really be doing here is use the extraction operator, opeartor>>(), along with the C++ IO streams. This, as opposed to using the C standard IO along with the read() function. For writing an object, use the insertion operator operator<<() instead of the C write() function.
For working with strings use std::string. This class provides operator<<() and operator>>(). So, you can say std::string s and then io << s and io >> s where io is some C++ IO stream object. This will do The Right Thing(tm). The philosophy here is that the std::string class knows better than you, a user, how to serialize a std::string object. So let it do it, with the << and >> operators.
Going on with the idea, you, as the author of User, know better than anyone else how to serialize a User object. So provide the << and >> operators for users of your class, as a service. "Users of your class" might well be you one week from now, when you have completely forgot how to properly serialize a User object. (Or, you think you remember but in practice you forgot a detail, causing a bug in your code). Example:
// in User.h
#include <string>
#include <iosfwd> // forward declarations of standard IO streams
namespace mine {
class User {
User(const std::string& name) : username(name) { }
friend std::ostream& operator<<(std::ostream&, const User&);
friend std::istream& operator>>(std::istream&, User&);
private:
std::string username;
};
std::ostream& operator<<(std::ostream& out, const User& u)
{
return out << u.username;
}
std::istream& operator>>(std::istream& in, User& u)
{
return in >> u.username;
}
} // namespace mine
From here on, to save a user to a file you say
std::ofstream f("filename");
User u("John");
f << u;
That's it. To read a user:
std::ifstream f2("filename");
f2 >> u;
It's a good practice to wrap your code in a namespace. IDEs give a good visualization of this issue, by showing how many symbols are visible with the auto-complete feature. You get to see how much of a mess there is in the global scope. By wrapping your code in a namespace you group it under a scope name, saving some more mess in the global name scope. It's just about being tidy. If you put your code in your own namespace then you can choose any name you want for a function, a class or a variable, so long as you haven't chosen it before. If you don't put it in a namespace then you need to share names with others. It's like a skunk declaring his own territory, only without the bed smell.
On that note I suggest you take off that using namespace std from your header. This brings all the symbols in the std namespace into scope of all files that #include the header. It's a bad practice. Only say using namespace std in implementation files, if you wish, but not in header files.
Granted, some will say even this is a bad idea. I personally think it's fine if you're aware of the fact you might have name clashes in that particular implementation file. But at least you know where that using statement is: it's in your implementation file, and it only causes clashes in that implementation file. It's sort of a gun, (a plastic water gun, but a gun nonetheless), only you can only shoot (wet) your own feet and no one else's. Which in my opinion is perfectly fine.
You can't read non-POD types like that. A string is not a POD type.
What are POD types in C++?
There are a few ways to read in strings properly, depending upon how they were stored.
For text files:
If the string is just a single word, separated on both sides by whitespace, you can use the plain old >> operator. If it's more than one word, you can store it on it's own line, and use getline.
For binary files:
Store the string in null terminated form. Read it one character at a time, checking for the null character. Or, prepend the string with an integer storing it's size. When you read it, first read in the integer, then read in that many characters.
string is an object, which means you're not writing it's contents.
Try writing an User and examine the file to see what I mean. What you're then reading are some pointers, that point to invalid memory locations.
Yes, the std::string class is not plain old data, in other words it contains pointers.
If you save/load the string class in this manner, the data pointed to won't be loaded/saved, only the value of the pointer.
Additionally sizeof(tempUser) won't include the size of the text pointed to by the strings.
Your solution is to change how you're reading/writing data.
One way is to use boost::serialization which handles datatypes like std::string.
Another way would be to write each string to a separate line in the text document yourself (not in binary mode) and then use readline to read them back in.
Rather than construct your own custom serialization code, something like Google Protocol Buffers might do what you want with less effort. It's ideal for passing around simple structured data from place to place.

Prevent third party from using my entire namespace

Although I've searched, I don't know if this is possible at all.
How can I prevent a library user from writing using namespace myns; anywhere in his/her code?
Let's say I implemented a library that encloses all its elements in a namespace called myns:
namespace myns
{
class MyClass
{
};
class string
{
};
}
This library will be used by another programmer. How can I force him/her to use
// somewhere in code
myns::MyClass myClass;
myns::string myString;
std::string stdString;
instead of
using namespace myns;
// somewhere in code
MyClass myClass;
string myString; // this would most likely be a mess
string stdString;
This would help with namespace collisions.
You can't. The standard says one can write using namespace myns; to get all the names, and there is nothing you can do about that.
If the user gets collisions after using namespace XXX;, that's their own fault. Generally, it is not possible to stop people from shooting themselves in the foot if they try to.
In the end, pulling in all names from some third party namespace is not something that happens on accident, but has been discouraged since about the dawn of time. If the user decides to do it anyways, they better know what they are doing. Really not the problem of the library maintainer.
One (questionable) workaround I can think of is replacing your namespace with a class or a struct of the same name and turning everything in your namespace into a (static) member of this class.
struct myns final
{
class MyClass
{
}
class string
{
}
private:
// private constructor, copy constructor and assignment operator
// ...
};
This would preclude programmers, using your library from writing using namespace myns but... well, like I said, I consider such a workaround to be quite questionable.
Note that users will still be able to use type aliases, such as:
using string = myns::string;

How can I access obect instances created from file output?

I am having trouble using file I/O to create instances of my classes for a game I am working on. It might well be a dumb question, but I cannot fathom out why the compiler seems to successfully creates the objects from the data stored in the text file and then I can't access them. (I took out the .display() function calls to test this, and added a simple cout << "Object created"; into the constructor to check something had been created.)
But the code trying to access the individual objects gives me Error: "identifier" is undefined when trying to access the objects member functions. I am probably doing something completely wrong and I would appreciate a push in the right direction, I have tried changing the syntax in the while loop for creating the object, but I haven't cracked it yet. Thank you in advance! Code below...
main.cpp
#include <iostream>
#include <string>
#include <fstream>
#include "Attributes.h"
using std::cout;
using std::endl;
using std::cin;
using std::ofstream;
using std::ifstream;
using std::getline;
using std::cerr;
int main() {
std::string line;
ifstream attdata;
attdata.open("data.txt");
if (attdata.is_open())
{
while (attdata.good())
{
getline (attdata, line);
Attributes * line = new Attributes;
}
attdata.close();
}
else cerr << "Unable to open file.";
health.display();
fatigue.display();
attack.display();
skill.display();
defence.display();
skilldef.display();
speed.display();
luck.display();
};
data.txt
health
fatigue
attack
skill
defence
skilldef
speed
luck
Atributes.h
#pragma once
#include <string>
class Attributes
{
public:
Attributes(void);
Attributes(std::string name, std::string shortName, std::string desc, int min, int max);
~Attributes(void);
void display();
private:
std::string m_nameLong;
std::string m_nameShort;
std::string m_desc;
int m_minValue;
int m_maxValue;
};
In C++, all your variables need to be declared by name in your code. You are declaring a bunch of pointer variables all named line in your loop, and then trying to use other named variables like health, fatigue, etc that have not been created.
I don't think you can directly create variables by name from a file like this, but you could read the file and create an array or vector of objects that contain the data from the file. You could pass the string read by getline() into your Attributes constructor, and then store the created pointers in an array or map that you can access later to call methods like display(). If you really want a variable called health in your code, it has to be declared somewhere in the code.
Another minor point is that you are reusing the variable name line (which you previously declared to be a std::string) in the loop scope. This may work, but is confusing and should be avoided. Call your pointer variable something else, like attItem.
For example:
Attributes * attItem = new Attributes(line);
attList.push_back(attItem);
You arent sending any of the information that you received to create the new object. Add a constructor that takes in a string with the information and then initialize Attributes like so:
Atrributes::Attributes(String data){
//parse string and initialize data here
}
Also, I would recommend not making your Attributes object have the same name as the variable that holds the data. Even if it's harmless (and im not sure that it is), its just not very clean.
C and C++ doesn't allow new names of variables to be created at runtime. Thus health in health.display(); can not come from reading a file.
What you can do is have a collection of Attributes (e.g. attList) and a function that finds the appropriate attribute for you:
Attribute health = attList.find("health");
(Or if you prefer to use a map, you could do:
Attribute health = attList["health"];
Another approach of course is to have attributes stored in each object, e.g.
class PlayerBase
{
private:
Attribute health;
Attribute speed;
...
public:
void SetAttribute(const string& name, const Attribute& attr);
};
Then you'd find the right attribute by comparing string name:
void SetAttribute(const string& name, const Attribute& attr)
{
if (name == "health") health = attr;
if (name == "speed") speed = attr;
...
}

C++ array in header file

I am doing a training exercise and am having trouble getting started on it. I have to write a program for an array data structure. There is a test harness provided and I need to implement the code for the data structure. I am not sure how to define an array in a header file
bellow is the test harness main.cpp which i can not edit
#include <fstream>
#include <iostream>
using namespace std;
// *****************************
// you need to create this class
// *****************************
#include "ArrayIntStorage.h"
int main(int argc, char **argv) {
// ***********************************
// non-sort read & then sort using std
// ***********************************
ifstream fin1("ACW2_data.txt");
ofstream out1("1-arrayUnsortedRead.txt");
//ofstream out2("2-arrayUnsortedRead-thenSTDSort.txt");
if(!fin1.is_open())
{
cout << "FAIL" << endl;
return 1;
}
ArrayIntStorage arrayStorage1;
arrayStorage1.setReadSort(false); // do not read sort
// read in int values into data structure
fin1 >> arrayStorage1;
// output int values in data structure to file
out1 << arrayStorage1;
// sort data structure using std
arrayStorage1.sortStd();
// output int values in data structure to file
out2 << arrayStorage1;
fin1.close();
out1.close();
out2.close();
any information on header files and how to use them with this main file would be much appreciated
Merci beaucoup
I'm pretty sure YOU are supposed to create the ArrayIntStorage.h header AND implement the matching ArrayIntStorage.cpp.
Based on the "// sort data structure using std" comment you are expected to use and create a wrapper over an appropriate stl container, something like std::vector.
Based on the "// do not read sort" comment, you should, by default, sort the vector after each insert (unless, of course, someone calls setReadSort(false) on your wrapper).
In addition to the interface described above, you still need to implement >> and <<.
UPDATE.
Reading you question at C++ pass variable from .cpp to header file you seem to be quite confused by all this...
First thing first, adding support for >> and << operators:
You do this by declaring these operators in your .h file:
friend std::ostream& operator<<(std::ostream &out, const ArrayIntStorage &a);
friend std::ifstream & operator>>(std::ifstream &, ArrayIntStorage &);
You then define their implementation in the .cpp file:
std::ostream& operator<<(std::ostream &out, const ArrayIntStorage &a)
{ return out; }
std::ifstream & operator>>(std::ifstream &, ArrayIntStorage &)
{ return in; }
Obviously, you need to add some proper code there, this is just to make it compile.
If it still doesn't compile, check if you have included the stream headers in your .h file:
#include <fstream>
#include <iostream>
Now for some general info:
Your array storage should be based on something like std::vector. The purpose of the >> and << function you need to implement is to add and retrieve int's from that container.
Since the ArrayIntStorage is a class, once you've established the interface you need ( the public member functions in the .h file) you should only look at the .h and .cpp to flesh out the implementation.
Once that is done, you don't need any of the "extern" madness the answers to your other question said.
Look at your main function. If creates an object of your class and the fin1 stream. It then calls the >> operator you've implemented. All of this is done with local variables.
This is how you "use the value of this variable from main.cpp". You call a member function of your class with that variable as a parameter.
And finally, if you have all these problems with understanding header files and link errors, are you sure you've started with the proper training exercise?
The header file ArrayIntStorage should be like below :-
The function signature may change according to the usage :-
// ArrayIntStorage.h - header file
class ArrayIntStorage
{
public :
ArrayIntStorage(); // this is the constructor
// You may skip this constructor, and use the default one
void setReadSort(bool bSort);
void sortStd()
// Add any public members if needed
private :
// Add any private members/ functions if needed
}
Marc,
http://www.cplusplus.com/doc/tutorial/ (which I mentioned in my comment) has let us down. They don't dicuss header-files as a topic in it's own right... however http://www.learncpp.com/cpp-tutorial/19-header-files/ does.
Basically a header file defines "the interface" of your class. It's put in a seperate file so that users of your class can include JUST this "interface definition" in there code... Like #include "ArrayIntStorage.h" for example. This allows the compiler to determine if they've got something wrong, like a miss-spelled method name, or passing a parameter of the wrong type... you know, all those compiler errors you've seen... yeah?
So you define WHAT your class does in the .h file... and then in the .cpp file you define HOW it does it.
Does that make sense?
Cheers. Keith.