C++ Writing Object to Binary File - c++

Problem:
Error: The "&" operator can only be applied to a variable or other l-value.
What I've tried:
dynamic_cast<char*>(e)
reinterpret_cast<char*>(e)
static_cast<char*>(e)
(char*) e
What I'm trying to do:
Write the array e.data (private) to a binary file.
Notes:
e.getSize() returns number of elements in array
e[] returns Employee object.
Code:
fstream fout;
fout.open(filename.c_str(), ios::out|ios::binary);
if(fout.good())
{
for(int i=0;i<e.getSize();i++)
{
fout.write((char*)&e[i], sizeof(e[i]));
}
}
fout.close();
Employee.h
class Employee {
friend std::ostream& operator<<(std::ostream&, const Employee &);
private:
int id;
char name[50];
char address[100];
char phone[20];
char department[100];
int salary;
public:
Employee();
~Employee();
Employee(int,char[],char[],char[],char[],int);
bool operator==(Employee&);
};
I'm lost at what to do, from what I remember fout.write((char*)&e[i], sizeof(e[i])); is how to write to binary files.
Edit:
e is declared like so:
MYLIB::Bucket<Employee> e;
template <class T>
class Bucket {
private:
T* bkt;
int size;
int capacity;
static const int stepsize = 10;
public:
Bucket();
~Bucket();
void push_back(const T&);
T operator[](int);
int getSize();
int getCapacity();
};
Edit 2:
fout.write(reinterpret_cast<char*>(e[i]), sizeof(e[i])); gives me line 122: Error: Using reinterpret_cast to convert from ? to char* not allowed. (Line 122 is the line just quoted)
Edit 3:
tempemp = e[i];
fout.write((char*)(&tempemp), sizeof(e[i]));
Compiles but gives a segmentation fault, I'll investigate why.
Compiles, the segmentation fault looks unrelated.

MYLIB::Bucket<Employee> e;
this seems to be a container. e[i] gives you an Employee by value. you need to get this object's address using &e[i] but you can'd do that since it's an r-value so you need to copy it to a non r-value:
Employee copye = e[i];
fout.write((char*)&copye, sizeof(e[i]));
Should work.
On a side note, this all looks like terrible code and I don't envy whoever needs to maintain or read it. A few points:
you should not be using the binary format of the in-memory object as your serialization format. Use a proper serialization format like protobuf or xml or json
Why pull your own strange containers when you can use std::vector std::list ? re-inventing the wheel is always bad
returning an element by value from a container creates copies which degrade performance.

I think that
T operator[](int);
is returning a temporary object that must be bound to something before an address can be taken
const Employee& emp = e[i];
fout.write((char*)&emp, sizeof(emp));
might work, assuming this answer is correct that taking a reference extends the life of a temporary object
An alternative might be to return a reference to the object, which would remove the creation of temporary objects
const T& operator[](int);

Related

Shallow copy a string array in the constructor

I have a string array (string references[10]) in my header file as a private variable of a class.
How can I shallow copy if I have a constructor in that class tome(string *initialList)?
I want to set references = initialList;
What is the best way to do it?
Header file:
#ifndef TOME_H
#define TOME_H
#include <string>
using namespace std;
class tome;
ostream &operator << (ostream &, const tome &);
class tome
{
public:
tome(string , int, string);
tome(string, int, string , string*);
~tome();
int getTomeSize();
string getSpell(int) const;
string* getReferences();
string getName();
string getAuthor();
tome operator+(string* add);
friend ostream &operator << (ostream &output, const tome &t);
void operator=(const tome &oldTome);
private:
string references[10];
string tomeName;
string author;
int spellsStored;
friend ostream &operator << (ostream &, const tome &);
};
#endif
tome.cpp Constructor:
tome::tome(string name, int tomeSize, string authorName, string* initialList)
{
tomeName = name;
author = authorName;
spellsStored = tomeSize;
}
An array, either raw or in form of std::array, always contains the data (in case of an array of pointers, the "data" is the pointers!), so if you have an array of std::string, you cannot shallow copy as std::string does not provide shallow copies.
For shallow copies, you need references or pointers (not considering visibility, adjust yourself as needed):
class A
{
std::array<std::string, 10> data; // using std::array for its superior interface...
};
class B
{
std::array<std::string, 10>* data; // references an array of some A
}
Obviously, you now need some life time management of whatever form to assure that the referenced A is not destroyed as long as the referencing B is still alive, or at least, as long as B still uses this reference. If you don't do this right, you end up either in undefined behaviour or with memory leaks...
You get this memory management for free if you use a smart pointer:
class C
{
std::shared_ptr<std::array<std::string, 10>> data;
};
Now different C (as many as you like) can share arbitrary data, it will be deleted as soon as all C referencing it are destroyed, but not earlier, and you are safe from both problems above. Shallow copies now are done by simply assigning the smart pointer to another one:
C::C(std::shared_ptr<std::array<std::string, 10>>& data) : data(data) { }
// ^^^^^^^^^^
// std::shared_ptr's constructor does the necessary stuff...
However, changes to the data in one C get visible to all other C sharing the same array. This can be desired in some cases, might lead to great surprises in other ones if you don't handle the matter carefully.
You might prefer deep copies instead to avoid trouble. I recommend using std::array because it has a superior interface similar to the one of std::vector, so you can easily assign correctly; let's extend above class A appropriately:
A::A(std::array<std::string, 10>& data) : data(data) { }
// ^^^^^^^^^^
// simply assign, std::array's constructor does the rest...
If you insist on having raw arrays:
class D
{
std::string[10] data;
D(std::string* data)
{
std::copy(data, data + 10, this->data);
}
};
Assuming we always have arrays of length 10 – you can get into great trouble if this condition is violated at some time somewhere. Better is passing the size together with the array and having appropriate checks. You see, std::array avoids all this trouble and additionally a mismatch between raw array and length being passed (on the other hand, you cannot pass sub-arrays this way; you could, though, provide an overload with two additional parameters size_t offset, size_t length to the approach below allowing to select sub ranges). If you want to be able to pass arrays of arbitrary lengths:
template <size_t N>
A::A(std::array<std::string, N>& data)
{
//static_assert(N <= 10); // if you don't want to discard surplus data silently...
//std::copy(data.begin(), data.end(), this->data.begin());
std::copy
(
data.data(),
data.data() + std::min(N, this->data.size()),
this->data.begin()
);
}
Finally: Appropriate typedefs can safe you quite some typing on one hand and, but more important, prevent you from errors (use constants as well):
class C
{
using Data = std::shared_ptr<std::array<std::string, 10>>;
Data data;
C(Data& data) : data(data) { }
};
class A
{
static size_t const DataLength = 10;
template <size_t N>
A(std::array<std::string, N>& data)
{
static_assert(N <= DataLength);
std::copy(data.begin(), data.end(), this->data.begin());
}
};

How do i create a class with certain rules for creating object?

I am a noob working on my very basic hobby program on chemestry, where i have created a class compound and added string compundname, but i want to design it in such a way that when i put in some invalid element in compund string, ex- NaMmO4 the compiler will not let me create object and instead come with an error something like "Mm invalid element"
Note:: my concern here is only with error handling.
example
compound sodiumsalt {"NMmO4"}
compiler should give error something like -
Mm is an Invalid element. cannot create object.
You are confused about the job of the compiler and what compiler-errors are.
Compiler errors are mostly sintax error and easy-to-spot running errors, where the compiler doesn't know what are you trying to do. To write the wrong string name will never be a compiler error. Also, it seems the name will be written at running time, which happens after compiler-time.
Might want to do something like this:
#include <iostream>
#include <exception>
using namespace std;
//some people are heavily against it, but I think is easier to use it if you are a beginner.
enum class elem_t{elem1, elem2, elem3};
class outOfBound: public exception
{
virtual const char* what() const throw()
{
return "Error: Accessed an element that doesn't exists.";
}
} noElem;
class Compound{
public:
Compound(elem_t* elems, int size){_elems = elems; _size = size;}
//can't include something is not part of elem_t
elem_t operator()(unsigned pos) const {if(pos < _size) return _elems[pos]; else throw noElem;}
int size() const{return _size;}
private:
elem_t* _elems;
int _size;
};
int main()
{
elem_t a[] = {elem_t::elem2, elem_t::elem1};
Compound first(a,2);
return 0;
}
The only basic thing I didn't do is a print() or operator<<, but it should be easy.

Error in C++ code when overloading operators

I'm trying to overload the '+' and '=' operators in my code, but I keep getting a run time error and the program crashes when running using VS2012 but runs perfectly in borland C 3.1.
Here's my code:
class employee{
int eid;
long esalary;
char * ename;
static char company_name[20];
static int emp_count;
public:
static char * getcompanyname(){
return company_name;
}
static int getempcount(){
return emp_count;
}
void set(int empid);
void set(long empsalary);
void set(char empname[]);
int getid();
long getsalary();
char * getname();
employee(int empid=0,long empsalary=0,char empname[]="NA"){
eid=empid;
esalary=empsalary;
ename=new char[strlen(empname)+1];
strcpy(ename,empname);
emp_count++;
}
employee(employee &ref){
eid=ref.eid;
esalary=ref.esalary;
ename=new char(strlen(ref.ename)+1);
strcpy(ename,ref.ename);
}
~employee(){
delete(ename);
}
employee operator+(employee &ref){
employee temp(*this);
temp.esalary=esalary+ref.esalary;
return(temp);
}
employee& operator= (employee &ref){
eid=ref.eid;
esalary=ref.esalary;
return * this;
}
}e1,e2,emp;
then in main:
emp=e1+e2;
To be honest, your code is invalid. It should not even compile, since it violates the reference binding rules: the + operator returns a temporary object, which cannot be passed through a non-const reference to the = operator. If you managed to compile this code, it simply means that your compiler(s) accepts it as an "extension" of the language.
To fix that specific error you have to add a bunch of const qualifiers to your declarations
employee operator +(const employee &ref) const {
employee temp(*this);
temp.esalary = esalary + ref.esalary;
return temp;
}
employee& operator =(const employee &ref){
eid = ref.eid;
esalary = ref.esalary;
return *this;
}
This will make your code valid from the C++ point of view, but it probably won't fix the crash, since the reason for the crash must be elsewhere.
Here's your crash-causing error: in the copy-constructor you did this
ename=new char(strlen(ref.ename)+1);
When you allocate an array with new, you have to use [] brackets, not ()
ename = new char[strlen(ref.ename) + 1];
You did it correctly in your first constructor, but then you for some reason used () instead of [] in your copy constructor. () in this context mean something completely different: it allocates a single char and initializes it to strlen(ref.ename) + 1 value.
BTW, is there a reason you are not copying ename in the copy-assignment operator?
Also, memory allocated with new[] must be freed with delete[]. Not with delete, but with delete[]. This is what your destructor should look like
~employee() {
delete[] ename;
}
Finally, you might be much better off using std::string for storing ename, instead of relying on raw memory management. (Unless you were specifically asked to do it that way).

defining operator [ ] for both reading and writing

In the book of "The C++ Programming Language", the author gave the following example along with several statements:
Defining an operator, such as [], to be used for both reading and writing is difficult where it is not acceptable simply to return a reference and let the user decide what to do with it.
Cref, is to help implement a subscript operator that distinguishes between reading and writing.
Why [] is difficult to be defined when to be used for both reading and writing?
How does the definition of class Cref help to solve this issue?
class String{
struct Srep;
Srep *rep;
public:
class Cref;
// some definitions here
void check (int i) const { if (i<0 || rep->sz<=i) throw Range( );}
char read( int i) const {return rep->s[i];}
void write(int i, char c){ rep=rep->get_own_copy(); rep->s[i]=c;}
Cref operator[] (int i){ check(i); return Cref(*this, i);}
char operator[] (int i) const{check(i); return rep->s{i];}
}
class String::Cref{
friend class String;
String& s;
int i;
Cref(String& ss, int ii): s(ss),i(ii) {}
public:
operator char( ) { return s.read(i);}
void operator=(char c){s.write(i,c);}
};
If you don't define a class Cref that solves this issue, then you have to do what std::map does:
template class <K,V> class map{
V& operator[](K const & key);
}
This returns a reference, which must be backed by a valid memory location, and therefore
std::map<string,string> m;
m["foo"];
assert(m.find("foo") != m.end());
The assertion will succeed (meaning, "foo" is now a valid key in the map) even though you never assigned something to m["foo"].
This counterintuitive behavior can be fixed by the Cref class in your example -- it can perform the appropriate logic to create m["foo"] only when you assign to the reference, and ensure that m.find("foo") == m.end() if you didn't perform some assignment when you tried to read the nonexistant m["foo"].
Likewise, in your String class (which is a reference-counted string -- strings share their string data, and a new copy is created when you change a string whose data is shared with another string), you'd have to make a copy when using operator[] to read characters. The use of the Cref class, allows you to ensure that you only make a copy when using operator[] to write.
String s;
s[0] = 5;
will call String::operator [](int) and then String::Cref::operator =(char).
However,
String s;
char c = s[0];
will call String::operator [](int) and then String::Cref::operator char().
When reading, String::Cref::operator char is called, and when writing String::Cref::operator = is called - this allows you to distinguish between reading and writing.
Why [] is difficult to be defined when to be used for both distinguish between reading and writing?
It's because the non-const operator[] is called whenever you have a non-const object, even if you're using it in a read-only fashion.

c++ save and load game with pointers in structs

I know I can use:
MyGame game; // the game object
//
ofstream out("mygame.bin", ios::binary);
out.write((char *)&game, sizeof(MyGame));
to save and load the game, but what if I have pointers inside MyGame structure? will the pointers just be saved but not the data it points to?
and: how to solve this?
You can't just write pointers to a stream and expect it to be magically done. You need to implement save/load methods in your objects. E.g:
class Serializable
{
virtual void save(std::ofstream& _out) const = 0;
virtual void load(std::ifstream& _in) = 0;
}; // eo class Serializable
// some game object
class MyObject : public Serializable
{
int myInt;
std::string myString;
virtual void save(std::ofstream& _out) const
{
_out << myInt << myString;
}; // eo save
virtual void load(std::ifstream& _in)
{
_in >> myInt >> myString;
}; // eo load
}; // eo class SomeObject
class MyGame : public Serializable
{
MyObject a;
MyObject b;
virtual void save(std::ofstream& _out) const
{
a.save(_out);
b.save(_out);
}; // eo save
virtual void load(std::ifstream& _in)
{
a.load(_in);
b.load(_in);
}; // eo load
}; // eo class MyGame
Assuming you have not overridden char * cast, yes this will most probably save only pointer and not data.
What you need is Serialization of your object. You can provide a method to marshal the state of object in a bit stream and write that out. And you also need to have method to restore the state back.
You may read more about serialization on wikipedia
Boost has a serialization library, with built in support for deep pointer save and restore, and proper serialization of pointers to shared data.
It's a rather extensive library, but you don't need to write that much code to start using it in your own projects. Well worth the learning effort for anything but the simplest serialization requirements in my opinion.
You could overload the stream out operator (<<) and stream out each individual field (and vice versa)
EDIT: here is a complete example...
#include <iostream>
#include <fstream>
#include <map>
using namespace std;
template <typename T>
void serialize(ostream& str, const T& field)
{
str.rdbuf()->sputn(reinterpret_cast<const char*>(&field), sizeof(T));
}
template <typename T>
void deserialize(istream& str, T& field)
{
str.rdbuf()->sgetn(reinterpret_cast<char*>(&field), sizeof(T));
}
class MyGame
{
public:
MyGame() : a(), b() {}
MyGame(int av, int bv) : a(av), b(bv) {}
friend ostream& operator<<(ostream& str, MyGame const& game);
friend istream& operator>>(istream& str, MyGame& game);
int getA() const { return a; }
int getB() const { return b; }
private:
int a;
int b;
};
ostream& operator<<(ostream& str, MyGame const& game)
{
serialize(str, game.a);
serialize(str, game.b);
return str;
}
istream& operator>>(istream& str, MyGame& game)
{
deserialize(str, game.a);
deserialize(str, game.b);
return str;
}
int main(void)
{
{
ofstream fout("test.bin", ios::binary);
MyGame game(10, 11);
fout << game;
}
{
ifstream fin("test.bin", ios::binary);
MyGame game;
fin >> game;
cout << "game.a: " << game.getA() << ", game.b: " << game.getB() << endl;
}
return 0;
}
You must understand the issues with this approach though, such as the resulting file will be platform specific (i.e. non-portable) etc.
Try game.serialize(out);. In your serialize member function call serialize of your pointer members.
Make a serializing function per type that needs to be persistent.
Call this for each member.
It is actually similar to serializing over network or visualizing for debug-purposes.
boost.serialize can help you.
"Naive" serialization that just dumps the value of pointers is never going to work because, when deserializing, those pointers will be invalid.
The general approach to this kind of problem would go like this:
Have each object that can be serialized in your game implement a serialize() virtual function (I am assuming all such objects will ultimately derive from the same base class).
Have the base class implement a get_serialized_id() public function. This function will use a static auto-incremented variable to generate a unique id for each object instance, but only the first time it is called (subsequent calls will just return the existing value).
Now, when serializing:
Start with a std::map<int, YourBaseClass*>. Add your game object to this map, using the value returned by get_serialized_id() for the key.
While the map contains objects that have not been serialized yet:
Take the first such object.
Serialize its get_serialized_id().
Serialize it by calling its implementation for serialize(). Have it persist its primitive data as usual. For data available through pointers, call get_serialized_id() on each object pointed to and just serialize the number returned from it. Also, add that object to the map.
This will result in a bunch of objects being serialized (in a "random" order) along with each one's "random" id.
When deserializing:
Start with a std::map<int, YourBaseClass*>. Read the first item in your saved file.
For each object pointed to by this first object, you know a unique id (this is what you serialized instead of a pointer). Fetch the item with this id from the saved file and deserialize it.
Recursively do this until all items have been fetched and deserialized from the saved file.
As each item has all its dependences deserialized in step 3 above, instantiate it as an object and add it to the map.
This will enable you to grab a pointer from the map given an item's id, which you can now use to set the pointer members of objects dependent on this item.
When the recursion ends, the last object in the map will be your main "game" object with all its pointers ready to go.
What you did is shallow copy, if you have pointers in your MyGame class, then a deep copy is a MUST!.
I suggest implementing a function or a set of functiions inside MyGame that will take care of saving its own data to a file,and you will only need to call it.
Thanks everyone for the fast and good answers, but a buddy of mine (who is helping me on this) told me we should do it in another way.
I just save the basics of the object and we recreate the rest in a function.
It's a card-game and to save the stack of cards we'll be saving the ID of the card only (not the objects) and just re-initializing each card when we read in the ID from the file.