Как правильно написать и прочитать экземпляр класса с vtable в QSharedMemory?

У меня есть класс, полученный из интерфейса

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;
};

Теперь я хочу написать программу, которая получит тот же экземпляр Implementer класс во всех экземплярах приложения. Я последовал примеру, предложенному здесь (второй), но в этом примере используется только один байт.

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();
}

Первый экземпляр работает нормально. Но он вылетает для второго на линии impl->foo(),

Я думаю, что причина - плохой актерский состав из void* к Implementer*, Но я не знаю, как сделать это правильно.

Какие-либо предложения?

редактировать

Я понял, что сбой, вызванный ошибкой сегментации, был результатом наследования, потому что без базового класса все работает просто отлично.

Редактировать 2

После некоторой отладки, дампа памяти и некоторых комментариев я понял, что проблема заключается в том, что во время выполнения первый экземпляр программы создает vtable в своем стеке и кладет vptr к его vtable, Второй экземпляр получает то же самое vptr что, к сожалению, указывает на некоторую случайную память (которая может быть выделена или нет).

1 ответ

Решение

Базовый класс с виртуальными функциями требует vtable, Расположение в памяти vtable или даже его существование зависит от реализации, поэтому вы получаете исключение при попытке доступа к функции через vtable,

Что вы можете сделать, это отделить данные и логику. Определите новый класс только с данными, поделитесь им и примените к нему некоторые функции.

Тем не менее, похоже, что у вас будут еще некоторые проблемы, так как вы планируете поделиться QMap как данные. Вероятно, он хранит свои данные в куче и не предоставляет интерфейс распределения памяти (по крайней мере, я не мог видеть). Это означает, что вы не сможете контролировать, где он размещает данные. Если вы уверены, что вам нужна структура карты, вы можете использовать std::map и предоставьте свой собственный распределитель памяти для карты, которая использует общую память, которую вы создали. Я только что написала c++ std map custom memory allocator в гугле и показывает некоторые решения. В SO также есть этот вопрос, который может вам помочь.

Другие вопросы по тегам