Simple serialization and deserialization in C++ - 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.

Related

How to make function return pointer to an array or object in C++?

I'm confused with a lot of answers found about what is a simple thing in other languages. I would like to get a reference to an object contained in class or struct. I've come up to using one of two different functions (here - getData()).
Question:
So, I am not sure which one to use, they appear to do the same thing. Other thing, is there some reason I should care because it's a union? And the most important question here is - I'm not sure about delete part I found in some answers, which scares me that this code example I've shown is not complete and will cause some memory leaks at some point.
#include <iostream>
#include <stdint.h>
using namespace std;
class settings_t {
private:
static const long b1 =0;
uint8_t setmap;
public:
uint8_t myBaseID;
uint8_t reserved1;
uint8_t reserved2;
};
class test1 {
public: //actually, I want this to be private
long v1;
settings_t st;
union {
uint8_t data[4];
uint32_t m1;
settings_t st1;
};
public:
uint8_t * getData() {
return data;
}
uint8_t (&getData2())[4] {
return data;
}
};
int main() {
test1 t1;
t1.data[2]=65;
uint8_t *d1 = t1.getData();
cout<<" => " << d1[2];
d1[2]=66;
uint8_t *d2 = t1.getData2();
cout<<" => " << d2[2];
}
The main difference of c++ from languages like c# or java is that it does not provide you with built in memory management (not a managed language). So, if the program allocates memory in c++, it is a responsibility of the program to release the memory when it is not needed. so, delete in your answers is based on this requirement.
However in you case, the getData() function returns a pointer to the data which is a part of the class test1. This is an array and the array will exist as long as the object of this class exist. Both versions of the getData will work.
You did not use any dynamic data allocation, the object t1 of type test1 was allocated on the stack of the main function and would exist till your program exits. You should not worry about 'delete'.
The difference between two methods you use is that the first method does not care about the array size it returns, whether the other does. For that reason the second methods has very limited practical use, but provides better syntactic checking.

Unhandled Exception: System.AccessViolationException : attempted to read or write protected

Problem: Getting an error when running my .exe
An unhandled exception of type 'System.AccessViolationException'
occurred in AddingWrapper.dll
Additional information: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
In the console it writes this:
Unhandled Exception: System.AccessViolationException : attempted to
read or write protected memory. This is often an indication that other
memory is corrupt. at gcroot (Add ^).. P$AAVAdd##(gcroot(Add^)) at
AddingWrapper.Adding(AddingWrapper, Int32* x, Int32* y)
Code snippet:
VB code:
Public Class Add
Public Function Adding(ByVal x As Double, ByVal y As Double) As Integer
Return x + y
End Function
End Class
AddingWrapper.h:
#pragma once
#include "stdafx.h"
class AddingWrapperPrivate;
class __declspec(dllexport) AddingWrapper {
private: AddingWrapperPrivate* _private;
public: AddingWrapper();
int Adding(int* x, int* y);
~AddingWrapper();
};
AddingWrapper.cpp
#include "stdafx.h"
#include "AddingWrapper.h"
#using "Class1.dll"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
class AddingWrapperPrivate {
public: msclr::auto_gcroot<Add^> add;
};
AddingWrapper::AddingWrapper()
{
_private = new AddingWrapperPrivate();
_private->add = gcnew Add();
};
int AddingWrapper:: Adding(int* x, int* y) {
return _private->add->Adding(*x, *y);
};
AddingWrapper::~AddingWrapper()
{
delete _private;
};
calling code:
#include "stdafx.h"
#include "AddingWrapper.h"
#include <iostream>
int main()
{
int *a = 0;
int *b = 0;
AddingWrapper *add;
int results = add->Adding(a,b);
std::cout << "here is the result";
std::cout << results;
return 0;
}
Could it be due to my Class1.dll in AddingWrapper.cpp is using VB.net? Or it's a question of other issues? All the other threads seem to all differ in answer (i.e one is suggesting the user account doesn't have all the rights to the computer). If ever I missed on of those thread, please link it to me, this error is killing me
I should also add this error is at run time not compile time.
In the main function, you are using a "null" object pointer and passing in NULL pointers - that will cause the error you are seeing.
int main()
{
int a = 1;
// ^^^ remove the pointer (and give it a "interesting" value)
int b = 2;
// ^^^ remove the pointer
AddingWrapper add; // remove the pointer (or allocate with new)
// ^^^ remove the pointer
int results = add.Adding(&a, &b); // pass in the address of the integers
// ^^^ syntax change
std::cout << "here is the result";
std::cout << results;
return 0;
}
The variable a, b and add where only pointers, pointing to nothing; this causes access violations. Changing them to be automatic objects ("on the stack") will fix this. If dynamic objects are needed, you can new them (and delete them afterwards); but favour library utilities such as std::shared_ptr and std::unique_ptr etc. to help manage the lifetime of the object.
Several things:
You haven't shown your VB code. Since you've written an unmanaged class, not a managed one, it seems likely that either the import is not correct, or that you're passing a bad pointer.
Why are you passing an int* to the wrapper, only to dereference it right there? Why not pass an int?
You're in C++/CLI, why are you not writing a managed class? You wouldn't need auto_gcroot, and you don't need to deal with DLL imports/exports: VB.Net would be able to see your class the same as it can see any .Net class, and reference it just as easily as you can reference any .Net library.
Edit
OK, it wasn't obvious that you were trying to call some VB.Net code from C++. I thought you were trying to go the other direction.
The problem is almost certainly that you're passing a bad pointer to AddingWrapper::Adding.
You don't need to pass a pointer for basic data types, so you can get rid of that entire thing if you want. The fact that it's a double in VB but an int in C++ is fine, C++/CLI knows that the VB code takes a double and will convert appropriately.
Also, note that you're not passing a pointer between managed and unmanaged code. You're passing a pointer from one unmanaged class to another unmanaged class (whatever calls AddWrapper, to AddWrapper), but across the managed/unmanaged border, you're passing a plain old int.

Returning boost::interprocess memory-mapped file from function?

How can I put this code in to a function so that I pass a file path and it returns the file-mapped bytes in to a char array? Whenever I have tried I can never read the contents once the function finishes?
using boost::interprocess;
using boost;
boost::shared_ptr<char> getBytes(const char* FilePath){
shared_ptr<file_mapping> fm(new file_mapping(FilePath, read_only));
shared_ptr<mapped_region> region(new mapped_region(*fm, read_only));
shared_ptr<char> bytes(static_cast<char*>(region->get_address()));
return bytes;
}
You probably need to go about your objective quite differently! Clearly you don't want to just delete the pointer to the memory mapped array which is what the boost::shared_ptr<char> initialized with the pointer to the base address would do. In fact, you probably should not release that pointer at all.
The other two objects you create will go out of scope when getBytes() is exited but these are the objects which actually cling to the shared memory. What you might want to do is to put the file_mapping and the mapped_region together into an object which is put into the returned boost::shared_ptr<char> as a deleter object: this way these two objects would live long enough to keep the pointed to array alive. Upon the deleter function being called the two objects would be released. Here is how this would roughly look like although I haven't checked whether these are indeed the correct interfaces:
struct shared_memory_deleter
{
shared_memory_deleter(char const* file)
: d_fm(new file_mapping(file, read_only))
, d_region(new mapped_region(*fm, read_only))
{
}
void operator()(char*) {
this->d_region.reset(0);
this->d_fm.reset(0);
}
shared_ptr<file_mapping> d_fm;
shared_ptr<mapped_region> d_region);
};
boost::shared_ptr<char> getBytes(const char* FilePath){
shared_memory_deleter deleter(FilePath);
shared_ptr<char> bytes(deleter.d_region->get_address(), deleter);
return bytes;
}
I'm not sure if this would work but it has, at least, a chance. It is probably not a good idea to do something like this. Instead, you are probably much better off wrapping the logic into an object and not using any shared pointers at all:
class shared_memory
{
public:
shared_memory(char const* name)
: d_file(name, read_only)
, d_region(d_file, read_only)
{
}
char const* buffer() const { return d_region.get_address(); }
};

reading objects from binary data

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)

Vector push_back error

So this is the situation.
I have a class
Class L_FullQuote
{
private:
vector<int> time;
..
}
and
Class B
{
L_FullQuote *Symbols[100];
void handle message()
}
Inside handle msg
i have this statement
Symbols[i]->time.push_back(2);
the code builds fine..but when i use the generated dll. the application just crashes..sometimes it takes me to a nxt poiner error in vector..but mostly the whole application just crashes.
It works fine without that line.
Please help
Thanks
You're already using vector, so why not take it one step further? Using std::vector will allow you to focus on writing your functionality, rather than worrying about memory management.
This example differs slightly from what you originally posted. Your original question class B has an array of 100 pointers that each must be initialized. In the example below, we create a std::vector of L_FullQuote objects that is initially sized to 100 objects in the constructor.
class L_FullQuote
{
public:
vector<int> time;
};
class B
{
public:
// Initialize Symbols with 100 L_FullQuote objects
B() : Symbols(100)
{
}
std::vector<L_FullQuote> Symbols;
void handle_message()
{
Symbols[i].time.push_back(2);
// other stuff...
}
};
L_FullQuote *Symbols[100];
Here you declare an array of pointer to L_FullQuote, but you never initialize any of the pointers, so when you call:
Symbols[i]->...
You are dereferencing an invalid pointer. Also note that you have declared time as private (though your code wouldn't even compile this way, s B as a friend of A I assume?)
Simply declaring an array of pointers does not initialize each element to point to a valid object. You need to initialize each one, something like:
for(int i = 0; i < 100; ++i) {
Symbols[i] = new L_FullQuote();
}
Only then do you have an array full of valid pointers. Don't forget to deallocate them though!
time is private member of class L_FullQuote, from class B you don't have access to that field