Reputation: 5
Hoping for some help as I feel like I've been banging my head against a door for ages to no avail.
The Goal: Use bitwise shift operators to extract a single int from a Dog object and Serialize it into a char pointer belonging to SerializedObject, save that char pointer to a .dat file with std::ofstream using std::ios::binary, then read that .dat file to a std::ifstream using std::ios::binary, and finally create a Dog object by Deserializing the SerializedObject.
The Issue:
I've looked over the program with my peers and we have nearly identical code. Nothing I do in terms of Dog::Serialize or Dog::CreateFromSO seems to have an effect on this result. I am truly at a loss.
Dog.h
#pragma once
#include <list>
#include "SerializedObject.h"
class Dog
{
public:
static const int SID = 1;
static Dog* NewDog();
static void DeleteAll() {}
static Dog* CreateFromSO(SerializedObject* tSO);
static Dog* FindDogFromID( int tID ) { return nullptr; }
int mAge = 0;
SerializedObject* Serialize();
private:
int mObjectID = 0;
Dog();
static std::list<Dog*> sAllDogs;
};
Dog.cpp
#include "Dog.h"
Dog* Dog::NewDog()
{
Dog* result = new Dog;
return result;
}
Dog::Dog() {
mAge = 14;
mObjectID = 1;
}
SerializedObject* Dog::Serialize()
{
SerializedObject* result = new SerializedObject;
result->mFullSize = sizeof(int);
result->mClassID = this->SID;
result->mBufferSize = sizeof(int);
result->mBuffer = new char[result->mBufferSize];
result->mBuffer[0] = (mAge >> 24) &0xFF;
result->mBuffer[1] = (mAge >> 16) &0xFF;
result->mBuffer[2] = (mAge >> 8) &0xFF;
result->mBuffer[3] = mAge & 0xFF;
return result;
}
Dog* Dog::CreateFromSO(SerializedObject* tSO)
{
Dog* result = new Dog;
result->mAge = 0;
for (int i = 0; i < 4; i++)
{
result->mAge <<= 8;
result->mAge |= tSO->mBuffer[i];
}
return result;
}
SerializedObject.h
#pragma once
struct SerializedObject
{
int mFullSize = -1;
int mClassID = -1;
int mBufferSize = -1;
char* mBuffer= nullptr;
};
main.cpp
#include "SerializedObject.h"
int main()
{
std::ofstream os;
os.open("APLO123.dat", std::ios::binary);
Dog* dog1 = Dog::NewDog();
SerializedObject* tSo = dog1->Serialize();
for (int i = 0; i < 4; i++)
{
os.put(tSo->mBuffer[i]);
}
os.close();
SerializedObject* tSo2 = new SerializedObject;
char* buffer = new char[sizeof(int)];
std::ifstream is;
is.open("APLO123.dat", std::ios::binary);
is.read(buffer, sizeof(int));
tSo2->mBuffer = buffer;
Dog* dog2 = Dog::CreateFromSO(tSo2);
}
The mBuffer just before Dog::Serialize return The debug shows the values 0 0 0 14
The DatFile Shows the PçN output to .dat
The buffer in main after ifstream.read Is read incorrectly 4 0 0 0
The value of result->mAge just before return of Dog::CreateFromSO Shows how the value is huge: 67108864
EDIT: Added Dog.h, the rest of Dog.cpp and SerializedObject.h
Upvotes: 0
Views: 382
Reputation: 15265
You serialization and deserialization works.
But there are many many design flaws that need to be fixed.
You are, for reasons that nobody can understand, using new all over the place. Although never necessary. And you never delete your allocated memory. And you do it in such a way that it is really hard to fix that.
Then, you do not understand that member functions should work on its own data members, and not on mebers of other classes.
In your "Dog" class, you have a function that creates a different dog. It does not set the value of "this" dog, but creates a new one. That is wrong. Even the compiler gives you a hint by emitting an error meesage for the line Dog* dog2 = Dog::CreateFromSO(tSo2);
. That is simply the wrong design.
If I look at your code, then I can see nowhere that mAge is initialized to some value. You seem to store indeterminate values in the file and then wonder what you read back.
To show your that the basic serialization / deserialization works, please see the below code:
#include <iostream>
#include <fstream>
struct SerializedObject {
size_t mFullSize{};
unsigned int mClassID;
size_t mBufferSize{};
char* mBuffer{};
};
struct Dog {
unsigned int SID{};
unsigned int mAge{};
SerializedObject* Serialize();
Dog* CreateFromSO(SerializedObject* tSO);
};
SerializedObject* Dog::Serialize() {
SerializedObject* result = new SerializedObject;
result->mFullSize = sizeof(int);
result->mClassID = this->SID;
result->mBufferSize = sizeof(int);
result->mBuffer = new char[result->mBufferSize];
result->mBuffer[0] = (mAge >> 24) & 0xFF;
result->mBuffer[1] = (mAge >> 16) & 0xFF;
result->mBuffer[2] = (mAge >> 8) & 0xFF;
result->mBuffer[3] = mAge & 0xFF;
return result;
}
Dog* Dog::CreateFromSO(SerializedObject* tSO) {
Dog* result = new Dog;
result->mAge = 0;
for (int i = 0; i < 4; i++)
{
result->mAge <<= 8;
result->mAge |= tSO->mBuffer[i];
}
return result;
}
int main() {
std::ofstream os;
os.open("APLO123.dat", std::ios::binary);
Dog* dog1 = new Dog();
dog1->SID = 1;
dog1->mAge = 42;
SerializedObject* tSo = dog1->Serialize();
for (int i = 0; i < 4; i++)
{
os.put(tSo->mBuffer[i]);
}
os.close();
SerializedObject* tSo2 = new SerializedObject;
char* buffer = new char[sizeof(int)];
std::ifstream is;
is.open("APLO123.dat", std::ios::binary);
is.read(buffer, sizeof(int));
tSo2->mBuffer = buffer;
Dog dogTemp;
Dog* dog2 = dogTemp.CreateFromSO(tSo2);
std::cout << dog2->mAge << '\n';
}
But this code is that wrong that it should never be used. Especially the memory leaks are a severe bug.
Unfortunately, you do not give enough information, so that I can show you a complete recoding. Especially because our teacher maybe want you to learn about serialization in general, using a framework or talking about factories later.
Anyway. Here some minmum improved example. Still not good and wrong design . . .
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
struct SerializedObject {
size_t mFullSize{};
unsigned int mClassID;
size_t mBufferSize{};
std::vector<char> mBuffer{};
};
struct Dog {
unsigned int SID{};
unsigned int mAge{};
SerializedObject Serialize();
void CreateFromSO(SerializedObject& tSO);
};
SerializedObject Dog::Serialize() {
SerializedObject result{};
result.mFullSize = sizeof(int);
result.mClassID = this->SID;
result.mBufferSize = sizeof(int);
result.mBuffer.resize(result.mFullSize);
result.mBuffer[0] = (mAge >> 24) & 0xFF;
result.mBuffer[1] = (mAge >> 16) & 0xFF;
result.mBuffer[2] = (mAge >> 8) & 0xFF;
result.mBuffer[3] = mAge & 0xFF;
return result;
}
void Dog::CreateFromSO(SerializedObject& tSO) {
mAge = 0;
for (int i = 0; i < 4; i++) {
mAge <<= 8;
mAge |= tSO.mBuffer[i];
}
}
std::string filename{ "APLO123.dat" };
int main() {
std::ofstream os(filename, std::ios::binary);
if (os) {
Dog dog1{ 1,42 };
SerializedObject tSo = dog1.Serialize();
for (int i = 0; i < 4; i++)
{
os.put(tSo.mBuffer[i]);
}
os.close();
std::ifstream is(filename, std::ios::binary);
if (is) {
SerializedObject tSo2;
tSo2.mBuffer.resize(sizeof(int));
is.read(tSo2.mBuffer.data(), sizeof(int));
Dog dog2;
dog2.CreateFromSO(tSo2);
std::cout << dog2.mAge << '\n';
}
else std::cerr << "\nError: Could not open '" << filename << "' for reading.\n";
}
else std::cerr << "\nError: Could not open '" << filename << "' fow writing.\n";
}
Upvotes: 1