Search code examples
c++qtshared-memoryvirtual-table

How to properly write and read class instance with vtable into the QSharedMemory?


I have a class derived from an interface

class Interface {
public:
  virtual void foo() = 0;
};

class Implementer : public Interface {
public:
  void foo() override { std::cout << "Hello world" << std::endl; }
private:
  int __some_int_member;
};

Now I want to write a program, which will get the same instance of Implementer class in all application instances. I followed the example suggested here (the second one), but in that example, only a single byte is being used.

int main(int argc, char **argv)
{
  QCoreApplication app(argc, argv);
  Implementer *impl = nullptr;
  QSystemSemaphore accessor("app_accessor", 1);
  accessor.acquire();
#ifndef QT_OS_WIN
  QSharedMemory mem_fix("my_class");
  if(mem_fix.attach())
  {
    mem_fix.detach();
  }
#endif
  QSharedMemory mem("my_class");
  if(!mem.attach())
  {
    mem.create(sizeof(Implementer));
    new(mem.data()) Implementer();
  }
  impl = (Implementer*)mem.data();
  accessor.release();

  impl->foo();
  return app.exec();
}

The first instance works fine. But it crashes for the second one on line impl->foo().

I think the reason is a bad cast from void* to the Implementer*. But I don't know how to do that correctly.

Any suggestions?

Edit

I realized, that the crash caused by the Segmentation fault was the result of inheritance because without the base class everything works just fine.

Edit 2

After some debugging, memory dump and some comments, I realized, that the problem is that in runtime the first instance of the program creates the vtable in its stack and puts the vptr to its vtable. The second instance gets the same vptr which, unfortunately, points to some random memory (that might be allocated or not).


Solution

  • A base class with virtual functions requires a vtable. The memory location of the vtable or even the existence of it is implementation-dependent, thus you get an exception when you try to access a function via vtable.

    What you can do is separate the data and logic. Define a new class with only data, share that and apply some functions on it.

    However, it seems like you are going to have some more issues since you are planning to share QMap as data. It probably stores its data on the heap and does not provide a memory allocator interface (at least I couldn't see). Meaning that you won't be able to control where it allocates the data. If you are certain that you need a map structure, you can use std::map and provide your own memory allocator to the map which uses the shared memory you've created. I've just written c++ std map custom memory allocator in google and it shows some solutions. There is also this question in SO that may help you.