Solved

C++ objects with virtual function and UNIX shared memory

Posted on 1997-06-03
1
443 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Grammars for C C++ and java 1 139
Microsoft C++ code failing in executable that worked 9 123
operator overload: incompatible type and too many params 5 90
learn programming 8 72
Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

726 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