Как правильно написать и прочитать экземпляр класса с 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 также есть этот вопрос, который может вам помочь.