reading objects from binary data - c++

I have been reading an array of SRD objects from a binary file - but since this was my first time doing so, I have modified a header making all its members public as I wasn't sure what would be going on. I have completed my assignment, all that is left is to make these members private and write methods that modify them. However, there is a problem.
For debugging purposes I put only 1 member private, and until I write all methods for it I will keep it that way. This member is simply an unsigned int C. When writing a method for returning it (getC() returns C), it is returning a value of 0000...3435973836, meaning it is not set?
So, I have an array of pointers to SRD created based on the number of objects in the binary file.
SRD *a;
...
a = new SRD[numOfRecords];
and the array is filled from the file...
for (i=0; i<numOfRecords; i++)
{
f.seekg(i * sizeof s);
f.read((char *)&a[i], sizeof s);
cout << a[i].getCC();
}
now, a[i].getCC() works when C is public, but making it private makes 000..3435...
meaning accessing it is not the problem, but it is not set in the fread from the previous for loop. I imagine I need some type of assignment operator, that sets these values, but I have no clue...

When you make the variable private, the SRD class is no longer plain old data (POD). Consequently, you have no guarantees regarding its in-memory representation, and therefore you cannot rely on f.read to work like this any longer.
I suggest that you add a read-from-stream method in your class and inside that method, read directly to the unsigned int member variable. Then, in the loop, you just call that method (passing the stream as a reference or a pointer).
EDIT, example as requested:
class SRD {
...
public:
void readFromStream(istream& f) {
f.read(&CC, sizeof CC);
}
private:
unsigned int CC;
};
Loop:
for (i=0; i<numOfRecords; i++)
{
a[i].readFromStream(f);
cout << a[i].getCC();
}

Actually, the problem was something else: the header was defined in a certain order, the first member was an array, while C was the second, and while debugging i first started with the C - and moving it from the second position to the above public one, changed the structure of the class.
so,
Class P
{
int i;
char c;
}
differs from
Class P
{
char c;
int i;
}
because the data in the binary file has a specific order, and when rearranging the order of the class defenition, a member (c) tries to access data intended for another member (i)

Related

Simple serialization and deserialization in C++

i need a way to serialize objects of different types (but the types deriving from the same class) and then deserialize them to the pointer of the base class, containing the deriving class. For example:
#include<iostream>
#include<fstream>
class One
{
public:
int a;
virtual void Func()
{
}
};
class One1: public One
{
char s[128];
void Func1(int l)
{
std::cout<<l<<'\n';
}
void Func()
{
Func1(156);
}
};
int main()
{
One* x = new One1;
x->Func();
char* y=(char*)x;
delete x;
/*std::ofstream out("test11.txt",std::ofstream::out | std::ofstream::trunc);
out.write(y,sizeof(One1));
out.close();
std::ifstream in("test11.txt",std::ifstream::in);
char* y1=new char[sizeof(One1)];
in.read(y1,sizeof(One1));*/
One* z=(One*)y/*1*/;
z->Func();
return 0;
}
This code outputs
156
156
But when I uncomment the comments (when I try to write to a file the char representation of the object and to read from this file then), the program outputs 156 and ends on segmentation fault when trying to execute z->Func();. I checked that the content of the variable y is different from y1. Why?
What is the cause of that issue and how can I address it (maybe by using some special libraries)?
1. Don't serialize derived classes by simply copying bytes
You can not simply write polymorphic objects by converting them to a byte array and then load them by a binary read. Classes with virtual functions store pointers to the implementations in a vtable. Dumping an instance of a derived class will result in dumping the pointers stored in the vtable, which - obviouly - doesn't have to be a valid pointer after you run the program once more. Accessing it after that will most probably yield a segmentation fault.
If you really want to use the easy way (directly reading and writing bytes), use POD classes.
2. Don't access invalid pointers
While the above is the most important part of the answer (because it will change your program entirely), there are also other things that need to be underlined. The command:
char* y=(char*)x;
Creates a char pointer that points to the address of x. It DOES NOT copy the object. Thus, when you later do:
delete x;
The pointer to y becomes invalid. When you later try to write that to a file:
std::ofstream out("test11.txt",std::ofstream::out | std::ofstream::trunc);
out.write(y,sizeof(One1));
You access memory that doesn't belong to you. At least not anymore, since you specificaly said you don't need it, by calling delete earlier.

c++ - How to use `this` to access member variables in an array of classes

Given a C++ class with assorted member data values and a static int counter, I'd like to have a clear() function that can walk all the elements of an array of these class objects clearing their data members.
So, for example, a class that looks like this and holds a chip's version information (yes, I know I probably need more setters and getters):
class __STA_version_t
{
public:
__STA_version_t() { count++; };
~__STA_version_t() {};
void setVerString( char* x ) { strncpy( verString, x, sizeof(verString)); verString[sizeof(verString)-1] = 0
void clearVerString() { memset( verString, 0x0, sizeof(verString) ); }
char* getVerString() { return verString; }
bool hasVersion() { return verString[0]; }
void clear()
{
for ( int i = 0; i < count; i++ )
{
// what goes here?
}
}
private:
static int count; // how many of these objects exist, need to know for clear().
char verString[20]; // station version as a string
UINT8 major_ver; // major version identifier (3 bits)
UINT8 minor_ver; // minor version identifier (6 bits)
UINT8 revision; // revision identifier (4 bits)
UINT8 chip_ident; // target chip identifier (3 bits)
};
Elsewhere initialize count thusly:
__STA_version_t::count = 0;
Now, create an array of there objects:
__STA_version_t versions[10];
First, just checking, count should equal 10 after this instantiation, right?
In the clear() function, I'd like to say something like:
this[i]->clearVerString();
this[j]->revision = 0;
// etc.
to clear each data member of each element of the array.
Can this be made to work? How?
The issue is that the class can't see outside its boundaries and the container is outside of the class' boundary.
You should use a standard container. Make the clear method clear data members in the class.
The standard containers have methods for determining the number of items.
See std::vector, std::list, std::map, etc.
What you are trying to do is not very "object oriented" IMO. I would argue that the class clear() member function you are trying to implement here should only clear the data of the instantiated object on which it is invoked. What you are trying to do is clear the data in all instantiations of your class, via calling clear() on any/one of them only?
A better approach here would be to store your objects in a std::vector<__STA_version_t>, and then write a static function on your class that either takes the vector as a parameter (ideally), or can access it globally somehow, called maybe clearAll(). Have that function iterate through the vector and call clear() on each object in the vector. The clear() function would then simply call clearVerString() etc on itself - eg:
this->clearVerString();
this->revision = 0; and so on (noting that you don't actually need to use the this pointer if you don't want to).

Trouble implementing min Heaps in C++

I'm trying to implement a minheap in C++. However the following code keeps eliciting errors such as :
heap.cpp:24:4: error: cannot convert 'complex int' to 'int' in assignment
l=2i;
^
heap.cpp:25:4: error: cannot convert 'complex int' to 'int' in assignment
r=2i+1;
^
heap.cpp: In member function 'int Heap::main()':
heap.cpp:47:16: error: no matching function for call to 'Heap::heapify(int [11], int&)'
heapify(a,i);
^
heap.cpp:47:16: note: candidate is:
heap.cpp:21:5: note: int Heap::heapify(int)
int heapify(int i) //i is the parent index, a[] is the heap array
^
heap.cpp:21:5: note: candidate expects 1 argument, 2 provided
make: * [heap] Error 1
#include <iostream>
using namespace std;
#define HEAPSIZE 10
class Heap
{
int a[HEAPSIZE+1];
Heap()
{
for (j=1;j<(HEAPISZE+1);j++)
{
cin>>a[j];
cout<<"\n";
}
}
int heapify(int i) //i is the parent index, a[] is the heap array
{
int l,r,smallest,temp;
l=2i;
r=2i+1;
if (l<11 && a[l]<a[i])
smallest=l;
else
smallest=i;
if (r<11 && a[r]<a[smallest])
smallest=r;
if (smallest != i)
{
temp = a[smallest];
a[smallest] = a[i];
a[i]=temp;
heapify(smallest);
}
}
int main()
{
int i;
for (i=1;i<=HEAPSIZE;i++)
{
heapify(a,i);
}
}
}
Ultimately, the problem with this code is that it was written by someone who skipped chapters 1, 2 and 3 of "C++ for Beginners". Lets start with some basics.
#include <iostream>
using namespace std;
#define HEAPSIZE 10
Here, we have included the C++ header for I/O (input output). A fine start. Then, we have issued a directive that says "Put everything that is in namespace std into the global namespace". This saves you some typing, but means that all of the thousands of things that were carefully compartmentalized into std:: can now conflict with names you want to use in your code. This is A Bad Thing(TM). Try to avoid doing it.
Then we went ahead and used a C-ism, a #define. There are times when you'll still need to do this in C++, but it's better to avoid it. We'll come back to this.
The next problem, at least in the code you posted, is a misunderstanding of the C++ class.
The 'C' language that C++ is based on has the concept of a struct for describing a collection of data items.
struct
{
int id;
char name[64];
double wage;
};
It's important to notice the syntax - the trailing ';'. This is because you can describe a struct and declare variables of it's type at the same time.
struct { int id; char name[64]; } earner, manager, ceo;
This declares a struct, which has no type name, and variables earner, manager and ceo of that type. The semicolon tells the compiler when we're done with this statement. Learning when you need a semicolon after a '}' takes a little while; usually you don't, but in struct/class definition you do.
C++ added lots of things to C, but one common misunderstanding is that struct and class are somehow radically different.
C++ originally extended the struct concept by allowing you to describe functions in the context of the struct and by allowing you to describe members/functions as private, protected or public, and allowing inheritance.
When you declare a struct, it defaults to public. A class is nothing more than a struct which starts out `private.
struct
{
int id;
char name[64];
double wage;
};
class
{
public:
int id;
char name[64];
double wage;
};
The resulting definitions are both identical.
Your code does not have an access specifier, so everything in your Heap class is private. The first and most problematic issue this causes is: Nobody can call ANY of your functions, because they are private, they can only be called from other class members. That includes the constructor.
class Foo { Foo () {} };
int main()
{
Foo f;
return 0;
}
The above code will fail to compile, because main is not a member of Foo and thus cannot call anything private.
This brings us to another problem. In your code, as posted, main is a member of Foo. The entry point of a C++ program is main, not Foo::main or std::main or Foo::bar::herp::main. Just, good old int main(int argc, const char* argv[]) or int main().
In C, with structs, because C doesn't have member functions, you would never be in a case where you were using struct-members directly without prefixing that with a pointer or member reference, e.g. foo.id or ptr->wage. In C++, in a member function, member variables can be referenced just like local function variables or parameters. This can lead to some confusion:
class Foo
{
int a, b;
public:
void Set(int a, int b)
{
a = a; // Erh,
b = b; // wat???
}
};
There are many ways to work around this, but one of the most common is to prefix member variables with m_.
Your code runs afoul of this, apparently the original in C passed the array to heapify, and the array was in a local variable a. When you made a into a member, leaving the variable name exactly the same allowed you not to miss the fact that you no-longer need to pass it to the object (and indeed, your heapify member function no-longer takes an array as a pointer, leading to one of your compile errors).
The next problem we encounter, not directly part of your problem yet, is your function Heap(). Firstly, it is private - you used class and haven't said public yet. But secondly, you have missed the significance of this function.
In C++ every struct/class has an implied function of the same name as the definition. For class Heap that would be Heap(). This is the 'default constructor'. This is the function that will be executed any time someone creates an instance of Heap without any parameters.
That means it's going to be invoked when the compiler creates a short-term temporary Heap, or when you create a vector of Heap()s and allocate a new temporary.
These functions have one purpose: To prepare the storage the object occupies for usage. You should try and avoid as much other work as possible until later. Using std::cin to populate members in a constructor is one of the most awful things you can do.
We now have a basis to begin to write the outer-shell of the code in a fashion that will work.
The last change is the replacement of "HEAPSIZE" with a class enum. This is part of encapsulation. You could leave HEAPSIZE as a #define but you should expose it within your class so that external code doesn't have to rely on it but can instead say things like Heap::Size or heapInstance.size() etc.
#include <iostream>
#include <cstdint> // for size_t etc
#include <array> // C++11 encapsulation for arrays.
struct Heap // Because we want to start 'public' not 'private'.
{
enum { Size = 10 };
private:
std::array<int, Size> m_array; // meaningful names ftw.
public:
Heap() // default constructor, do as little as possible.
: m_array() // says 'call m_array()s default ctor'
{}
// Function to load values from an istream into this heap.
void read(std::istream& in)
{
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
}
return in;
}
void write(std::ostream& out)
{
for (size_t i = 0; i < Size; ++i)
{
if (i > 0)
out << ','; // separator
out << m_array[i];
}
}
int heapify(size_t index)
{
// implement your code here.
}
}; // <-- important.
int main(int argc, const char* argv[])
{
Heap myHeap; // << constructed but not populated.
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
myHead.write(std::cout);
return 0;
}
Lastly, we run into a simple, fundamental problem with your code. C++ does not have implicit multiplication. 2i is the number 2 with a suffix. It is not the same as 2 * i.
int l = 2 * i;
There is also a peculiarity with your code that suggests you are mixing between 0-based and 1-based implementation. Pick one and stick with it.
--- EDIT ---
Technically, this:
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
is poor encapsulation. I wrote it this way to draw on the original code layout, but I want to point out that one reason for separating construction and initialization is that it allows initialization to be assured that everything is ready to go.
So, it would be more correct to move the heapify calls into the load function. After all, what better time to heapify than as we add new values, keeping the list in order the entire time.
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
heapify(i);
}
Now you've simplified your classes api, and users don't have to be aware of the internal machinery.
Heap myHeap;
myHeap.load(std::cin);
myHeap.write(std::cout);

Passing integer by reference to a class in c++

I have a thread-class Buffer (own made class), and many derived classes such as BufferTypeA, BufferTypeB...
Since I have to synchronize them in a certain order, I'm giving any of them an integer which represents the order to run certain task. I also have to know inside each thread Buffer which one is next to run the task, so I'm passing every BufferType a reference to an integer which all of them must share and I didn't want to make it Global.
I got lost at any point and I don't see where.
First I create all the BufferTypes from a class where I also define that shared integer as:
int currentThreadOrder;
And when creating the BufferTypes:
int position = 0;
if (NULL == bufferA) {
bufferA = new BufferTypeA(&currentThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferB) {
bufferB = new BufferPos(&currentThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferC) {
bufferC = new BufferRtk(&currentThreadOrder, ++position,
waitCondition);
}
Then, in BufferTypeA header:
class BufferTypeA: public Buffer {
public:
BufferTypeA(int currentThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//..
}
And in cpp file:
BufferTypeA::BufferTypeA(int currentThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition):
Buffer(currentThreadOrder, threadConnectionOrder, waitCondition) { }
Now I'll show Buffer header:
class Buffer: public QThread {
public:
Buffer(int &currentThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//...
protected:
QWaitCondition *waitCondition;
int threadConnectionOrder;
int &currentThreadOrder; // Shared address
}
And finally the cpp:
Buffer::Buffer(int &currentThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition) {
this->threadConnectionOrder = threadConnectionOrder;
this->waitCondition = waitCondition;
this->currentThreadOrder = currentThreadOrder;
}
And the error I'm getting is error: uninitialized reference member Buffer::currentThreadOrder.
I'm embarrased to ask, because it's going to be a simple problem with pointers and addresses, but I can't see where the problem is, so please help.
When you create a class with a data-member that is a reference, the reference needs to be assigned a value in the constructor initializer list.
References have to be given a value when they are created, they are not pointers. They have to start with a value and that value cannot be changed (while the contents that is pointed to by that value can be changed).
Essentially you can think of a reference as an alias for an existing variable. You can't give a friend a nickname if you don't have a friend :)
RESPONSE TO COMMENT:
You don't "share a reference" between objects. Each object will have its own reference to the same variable. When you "pass by reference" you are telling the compiler that you want the variable in your function to actually be the variable in your outer scope, rather than creating a new variable by value. This means that you only have one variable at one memory location. The reference is just memory in some other place that forwards you to that same memory location.
Think of this as call forwarding... I can have 15 phone numbers in 15 different countries. I can set them all up to forward calls to my cell in the US. So, people are calling me no matter which number they call.
Each of your classes just has another reference to forward the "phone calls" or variable reads/writes to that same memory location. So, you're not sharing a reference between classes, you're making sure that each class HAS a reference to the same underlying memory location.
Back to the metaphore, each class won't have the same phone, but each class' phone will forward to the same number (variable) none-the-less which lets them all set/get the same value in the end.
RESPONSE II:
Here's a simple example to get your head going, it's pretty easy to apply to your classes. I didn't compile it but it should work minus a typo or two possibly.
class A
{
public:
A(int& shared) : m_shared(shared)
{
//No actions needed, initializer list initializes
//reference above. We'll just increment the variable
//so you can see it's shared in main.
m_shared += 7;
}
void DoSomethingWithIt()
{
//Will always reflect value in main no matter which object
//we are talking about.
std::cout << m_shared << std::endl;
}
private:
//Reference variable, must be initialized in
//initializer list of constructor or you'll get the same
//compiler error again.
int& m_shared;
};
int main()
{
int my_shared_integer = 0;
//Create two A instances that share my_shared_integer.
//Both A's will initialize their internal reference to
//my_shared_integer as they will take it into their
//constructors "by reference" (see & in constructor
//signature) and save it in their initializer list.
A myFirstA(my_shared_integer);
A mySecondA(my_shared_integer);
//Prints 14 as both A's incremented it by 7 in constructors.
std::cout << my_shared_integer << std::endl;
}
you pass a pointer int* as 1st argument to BufferTypeA, which expects and int, while you said in your question you meant to use a int&. To do this, the ctor of BufferTypeA should take a int& and initialise it in an initialisation list (i.e. not within the { } part of the ctor) like
class BufferType {
int &Ref;
public:
BufferTypeA(int& ref) : Ref(ref) { /* ... */ }
};
and in your construction of BufferA you must not pass an address, but the reference, i.e.
int counter;
Buffer = new BufferType(counter);
You want code like this:
Buffer::Buffer(
int &currentThreadOrder0,
const int threadConnectionOrder0,
QWaitCondition *const waitCondition0
) :
threadConnectionOrder(threadConnectionOrder0),
waitCondition(waitCondition0),
currentThreadOrder(currentThreadOrder0)
{}
The reason is related to the reason you cannot write
const double pi;
pi = 3.14;
but can write
const double pi = 3.14;
A reference is typically implemented as a constant pointer, to which one cannot assign an address after one has initialized the pointer. Your version of the code assigns, as in the first pi example. My version of the code initializes, as in the second pi example.

how can I compare an instance of a class with a char * variable in c++?

I need help on my homework assignment.I need to write the code for a parking garage. and in order to write it I need to copare the input of my instance of the class"Parkbox",which has been created on the on the heap and via another class "Parkinggarage" , with a #define EMPTY "--------".
So this is my code:
the Parkbox definition:
class Parkbox{
char *license_plate; // car's license plate
public:
Parkbox(); //Default CTOR
Parkbox(char * ); // CTOR
~Parkbox(); // DTOR
void show();
};
and ParkingGarage:
class ParkingGarage{
Parkbox ***p2parkboxes;
and my CTOR or ParkingGarage in order to create Parkbox instance on the heap:
ParkingGarage::ParkingGarage(const int rw,const int clm, const int plns){
p2parkboxes = new Parkbox **[plns];//points to the floors and make the arraq of p2p same size as number as floors
for(int p=0;p<plns;p++){
p2parkboxes[p]= new Parkbox *[plns];//for each Plane creats an array of pointer that is same with the num of rows
for(int r=0;r<rw;r++)
p2parkboxes[p][r]= new Parkbox [clm];
}
}
void ParkingGarage::find_next_free_parking_position()
{
for(int f=0;f<dimensions_of_parkhouse[0];f++){
for(int r=0;r<dimensions_of_parkhouse[1];r++){
for (int c=0;c<dimensions_of_parkhouse[2];c++){
//p2parkboxes[f][r][c] is the instance of the class Pakbox
if(p2parkboxes[f][r][c]==EMPTY)
{
next_free_parking_position[0]=p;
next_free_parking_position[1]=r;
next_free_parking_position[2]=c;
}
}
}
}
}
how ever at the point "p2parkboxes[f][r][c]==EMPTY" it gives me error that " no operator "==" matches these operands", .
then how can I compare a class instance directly with another variables like EMPTY?
I do not know if I am clear for you or not.
But please help me because if I do not solve this problem I can not continue completing my code.
In general, you can only compare two same types. With operator overloading, you can define your own compare operator to work with this problem. C++ cannot compare two classes in default though.
So it seems in your code that you are comparing char* type with your class type. You should compare char* with another char*. If it's treated as string, you should use strcmp for increased safety
You'll have to create a matching operator overload. The compiler error should name you the parameters, but the member should most likely look a bit like the following:
bool Pakbox::operator==(const char *other) {
return !strcmp(other, this->memberstring);
}
Note that memberstring has to be replaced by an actual member holding what's in that lot.