我有一个从接口(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;
};
现在我想编写一个程序,它将在所有应用程序实例中获取相同的 Implementer
类实例。我按照建议的例子 here (第二个),但在那个例子中,只使用了一个字节。
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*
的错误转换。但我不知道如何正确地做到这一点。
有什么建议吗?
编辑
我意识到,Segmentation fault 导致的崩溃是继承的结果,因为没有基类一切正常。
编辑2
经过一些调试、内存转储和一些注释后,我意识到,问题是在运行时程序的第一个实例在其堆栈中创建了 vtable
并将 vptr
到它的 vtable
。第二个实例获得相同的 vptr
,不幸的是,它指向一些随机内存(可能已分配或未分配)。
最佳答案
具有虚函数的基类需要一个vtable
。 The memory location of the vtable or even the existence of it is implementation-dependent ,因此当您尝试通过 vtable
访问函数时会出现异常。
您可以做的是将数据和逻辑分开。定义一个只有数据的新类,共享它并在其上应用一些功能。
但是,由于您计划将 QMap
作为数据共享,因此您似乎还会遇到更多问题。它可能将其数据存储在堆上并且不提供内存分配器接口(interface)(至少我看不到)。这意味着您将无法控制它在何处分配数据。如果您确定需要映射结构,则可以使用 std::map
并为使用您创建的共享内存的映射提供您自己的内存分配器。我刚刚在 google 中编写了 c++ std map custom memory allocator
,它显示了一些解决方案。还有this SO 中的问题可能对您有帮助。
关于c++ - 如何正确地将带有 vtable 的类实例写入和读取到 QSharedMemory 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57298775/