Solved

C++ objects with virtual function and UNIX shared memory

Posted on 1997-06-03
1
411 Views
Last Modified: 2012-08-14
I want to make some objects in shared memory. These objects have got virtual functions. The first process (server) makes shared memory and objects in it. Other processes attach this memory and use objects. Can I make these processes not copy or fork of server process?
For example:
class a {
public:
   virtual void func();
};

class b : public a {
   virtual void func();
};
...
Server:
char *ptrshare;   // pointer to shared memory
a *ptra=new a;
b *ptrb=new b;
...
memcopy(ptrshare,ptra,sizeof(a));
ptrshare+=sizeof(a);
memcopy(ptrshare,ptrb,sizeof(b));
ptrshare+=sizeof(b);
...

Client :
char *clientptrshare;
a *ptra=(a *)clientptrshare;
ptra->func();  // ?!!!

I tried this in HP UX. class a was in module a.cpp,
b - b.cpp etc.
If I make programs:
CC server.o a.o b.o c.o -o server
CC client.o a.o b.o c.o -o client
That's OK.
CC server.o a.o b.o c.o -o server
CC client.o a.o c.o b.o -o client
That's wrong.
0
Comment
Question by:viaches
1 Comment
 

Accepted Solution

by:
cwestin earned 100 total points
ID: 1163813
What was wrong with the last link line?  You've got to be more explicit.

Yes, this can be done without copying or forking(), but I need to know more details.  You also need to be aware that this may not be portable, depending on the solution you choose.

I suspect your problem has to do with the order of the link line.  Do you understand how virtual functions work?  i.e., do you realize that in your class instances, there is an (invisible) pointer, known as the "vtable pointer" to a structure full of function pointers (the vtable)?  The issue is that the address of the vtable may differ in the different binary images.  When you create "server" the vtable for class a is at a certain adress, call it servera.  But in "client" the vtable for the class may reside at a different address, call it clienta.  When you instantiated the class, the instance's vtable was initialized to point to servera.  But servera != clienta.  Therefore, when client tries to invoke a->virtualfunc(), the vtable pointer is pointing somewhere else.

In general, because of this, and some other related problems that crop up with the use of shared libraries, you can't use C++ virtual functions on objects in shared memory unless the binaries are all identical (implying that the vtables will always be at the same address.)  You can however get the same effect by introducing a level of indirection.  I've used this technique before:  I declare the virtual function explicitly.  Declare a structure that contains the function pointers you want virtual:

struct myfuncs
{
  void (*foo)(myclass *pthis, int x, int y);
   int (*bar)(myclass *pthis, char *p);
};

Initialize this structure with your functions.

const myfuncs MyFuncs =
{
  fooFunc, barFunc
};

  You must have an instance of this in each binary that the functions will be called from.  Then, create invocation macros for the virtual functions that look like this:

#define myclassfoo(pthis, x, y) ((*MyFuncs.foo)(pthis, x, y))
#define myclassbar(pthis, p) ((*MyFuncs.foo)(pthis, p))

Use these macros to call your "virtual functions."  This works because in each image, the macro will be using the locally linked reference to the function pointer rather than one in another process.

If you want polymorphism, things get a bit more complicated.  Then, you have to more closely copy the effects of using a real vtable, but without using pointers.  I've also used this technique before.  You have to assign unique integers to each vtable involved.  In your class instance, put an integer variable that will serve as an explicit "vtable index" (instead of a vtable *pointer*.)  When you instantiate the class, set the vtable index appropriately.  Create invocation macros that use the index to index into an array of pointers to vtables such as the one above.  You have to create and initialize the array of vtable pointers in each process, where it will have the correct local values.  Then, the invocation macros look like this:

#define abstractfoo(pthis, x, y) (*((vtable_type *)vtable_array[(pthis)->vtable_index]).foo)(pthis, x, y))

With
const void *vtable_array[] =
{ (void *)foo_vtable, (void *)bar_vtable, ...};

Again, each process will have its own correct local copy of the function pointers and vtables.  This will also work as a technique to make polymorphism work for classes in shared libraries on platforms that load the library into different addresses in each process.

0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now