Shared memory and C++

Hello,

I need some help with c++ objects instantiated into a shared memory segment.

I wrote a class that acts as an interface to the common (shared mem.) operations.

Everything works fine until I needed to copy a dynamically created array of structs that also contains subarrays of the same type and two integer members.

I created a clone function that receives origin and destination and uses memcpy to “clone” the whole structure.

Bellow I put some working code that behaves exactly like the original.


struct test2
{
	int a;
};

struct test
{
	int a;
	int b;
	test2 *c;
};


void Clone(test* from, void *destination)
{
memcpy (destination, from, sizeof(NodeInformation));
				test *to	= (test *) destination;

				to->c						= (test2 *) calloc(10 , sizeof(test2));

				memcpy (to->c, from->c , 10 * sizeof(test));
}

The destination parameter is a pointer to a shared memory segment. The function should copy the origin content to the destination using struct test architecture.

The first line (of Clone()) works ok. I am able to see its content a the memory position.

Memory:

destination = 0xb7fde000
to = 0x08049460
to = 0xb7fde000
to.a = 123
to.b = 234

to.c = 0x08053170 // t.c = array of test2

As you can see to.c points to a local memory segment, not to a part of the shared memory as it should be.

What I want to achieve is to get to.c point to the righ direction but I don’t know how. I used calloc() to initialize to.c. Without this I get a segfault.

Main code


SharedMemory *sm1 	= new SharedMemory(SHAMEM_ID, 1600, true);
		void *pool			= sm1->Get();
		test *tp			= (test *)pool;
		test *t				= new test;
		t->a =  123;
		t->b = 234;
		t->c = (test2 *) malloc(sizeof(test2) * 10);
		t->c[0].a =  777;
		t->c[7].a =  888;
		Clone(t, pool);

Both test.a and test.b field are copied correctly but the array always point to invalid places.

What am i doing wrong?

Thanks in advance.

What you are trying to do is a deep copy of a structure. In that case you have to provide some storage that c points to. This is not a C++ issue BTW, you would have the same issue in C.

Thank you.

How can I provide that storage?

I though it was a C++ memory management issue because I did something similar in C but with less complexity and correct results.

I don’t understand why it stop pointing to the right place when I did the casting.

I tried to do something like:



to->Table = (test2 *)((char)destination + 8);


  • 8 because I have two 4 bytes integers.

The code is wrong but at least I get to->Table points to destination + 8, inside the shared memory.

I still looking for the answer.

You have to allocate some space for it somewhere in shared storage. What you are trying to copy is not an object that is all of one piece in memory. It contains a pointer that points to another piece. Therefore your destination object must also be two pieces, one for the base object and one for the auxiliary structure pointed to from the base object.

What C++ could do for you is encapsulate the copying in a deep-copy method.

Also if you find yourself doing casting in C++, most of the time you are doing something wrong.

Thank you ken yap. Now I get the point.

Also if you find yourself doing casting in C++, most of the time you are doing something wrong.

I am sorry but I think I didn’t understand you. Are you telling me that the necessity of casting in my code could be because of a bad use of the tool (C++) or the lack of practice in this particular field?

Thanks again.

It means that most of the time, casting is not needed in C++. The typing rules should handle most of the type coercions automatically, or the coercions should coded in a few places. If you find yourself needing a cast, perhaps something is wrong with the code.

Also if an arbitrary area of memory is declared as void *, this is automatically compatible with any typed pointer, and you don’t need a cast. (Provided alignment constraints are adhered to.) malloc() returns a void * that is compatible with all typed pointers. Of course, you really should be using new() instead of malloc().

Finally.

I think I should write my own shared memory heap-like manager.

Doing the following I made it work properly.


SharedMemory *sm1 	= new SharedMemory(SHAMEM_ID, 1600, true);
void *pool		= sm1->Get();		test *tp			= (test *)pool;
tp->c			= (test2 *)(new SharedMemory ( SHAMEM_ID + 10, sizeof(test2) * 10, true ))->Get();		test *t			= new test;
t->a =  123;
t->b = 234;
t->c = (test2 *) malloc(sizeof(test2) * 10);
t->c[0].a =  777;
t->c[7].a =  888;
Clone(t, pool);

Yes, you’re right. I did the cast because I get a compilation error without it.
The following results in: invalid conversion from ‘void*’ to ‘test*’


test *to	= destination;

I used malloc() because I though there were something wrong with my C++ code.

Originally Clone() was not function, it was a method that uses new operator to dynamically allocate memory.

I also tried overloading new() and returning the start of the shared memory. It wasn’t work either. It will be crazy to write a function that updates the pointer in every method that manipulates the object so I voted to a simply structure that imitates straightforward memory allocation but as you saw it wasn’t that simple (at least for me).

This is bang on spot. If you don’t allocate space for the auxilliary object (the one it is pointing to) then you can not point there - it is a dangerous slot. If you copy the original address then moment you free the first variable’s heap space the second variable get s a dangling pointer - dangerous and a certain crash unless you mistakenly forget to legally delete the second object.

You not only need to allocate separate space (malloc), but also need to make sure that the pointer of the second object is not a copy of the pointer of the first object - it is only the object pointed to that will be the same. In other words, you can not find &(from->c) and &(to-c>) to match - if they match then something is wrong and you are in for deep trouble.


Infrared Sauna Portable sauna