0

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).

arsdever
  • 1,111
  • 1
  • 11
  • 32
  • Don't use `void*`. There's always a better way. – Jesper Juhl Jul 31 '19 at 21:03
  • @JesperJuhl I don't. The function `QSharedPointer::data()` returns the `void*` to the memory. – arsdever Jul 31 '19 at 21:04
  • @arsdever I think your answer lies in [this](https://stackoverflow.com/questions/1905237/where-in-memory-is-vtable-stored) question. The vtable is stored in local memory, and your second app instance tries to reach that space. – seleciii44 Jul 31 '19 at 21:38
  • @seleciii44 If so, could you please suggest some solution to the problem? – arsdever Jul 31 '19 at 21:44
  • @seleciii44 Finally I got your point. And I realized the whole problem. It's kinda bigger than I expected. But it didn't solve my problem. Now I am more confused. – arsdever Jul 31 '19 at 21:49
  • @arsdever why dont you separate data to share from the logic? Define a new class with only data, share that and apply some functions on it. in your example your implementer does not have any data. whats the point of having it shared? – seleciii44 Jul 31 '19 at 21:51
  • @seleciii44 In my project I work on there are some data I'm keeping in `Implementer` class. It is a simple `QMap<>`. I liked your advice and probably will implement my code in that way. For a clean Q&A please provide your solution into an answer that I could accept. – arsdever Jul 31 '19 at 21:58
  • @arsdever it is midnight in turkey and i am just about to sleep :) i will write it in the morning tomorrow. – seleciii44 Jul 31 '19 at 22:02
  • I would not do that thing above as means of interprocess communication. – Alexander V Aug 01 '19 at 03:36

1 Answers1

1

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.

seleciii44
  • 1,529
  • 3
  • 13
  • 26