在很多场合,我见过这种情况
class Foo
{
static void* ThreadFun(void* p)
{
Derived* args = (Derived*)p;
//do something with args.
//example
//cout << args->getname();
}
void function()
{
Base* args = new Derived();
args->setname("test");
pthread_t id;
int ret = pthread_create(&id, NULL, ThreadFun, (void*) args);
}
}
首先,是正确的C ++代码吗?还是我错过了什么?我做了一些读数,显然是将一个指向类的指针转换为void *导致信息丢失并在派生类上调用getname()可能是非法的。
如果我理解正确,他们的建议是这样的:
void function()
{
Base* args = new Derived();
args->setname("test");
void* pargs = (Base*)malloc(sizeof(*args)); // to be freed in ThreadFun
pargs = args;
pthread_t id;
int ret = pthread_create(&id, NULL, ThreadFun, pargs );
}
我真的不明白,我该怎么做呢?
答案 0 :(得分:3)
哦,哇......不,你的第二个例子泄漏了malloc()分配的内存,并且从评论中,如果你遵循这个建议,你将有空()你的new Derived()
分配在你认为你正在释放malloc()分配时在ThreadFun中。
关于将类指针转换为void *导致信息丢失......但事实并非如此。普通&amp;简单。失去的是编译器对该指针的含义的理解。如果你知道它意味着什么,你总是可以把它归还给它的正确类型&amp;恢复其全部功能,这正是第一个示例所做的。当ThreadFun()函数在新线程中启动时,它会将void *转换回其原始类型,即Derived *。
我注意到,当您最初调用new Derived()
分配时,您将返回指针指定为Base*
类型的指针。我假设class Derived
继承自class Base
,所以那里的赋值实际上会导致“信息丢失”,虽然它是Base*
类型的指针,但你会失去任何非多态的Derived
类的行为。但是当你将它转换回ThreadFun()中的真实类型时,它将重新获得其全部功能。请注意,如果您分配了一个new Base
对象并使用它启动了新线程,并且在ThreadFun()中将其转换为Derived*
,编译器会让您这样做,但是你会有未定义的行为......可能是崩溃。因为(由于pthreads接口)你必须通过void *,所以即使使用C ++样式转换,也没有类型检查的安全性。所以你可以把那个void *转换成你想要的任何东西,编译器会让你。但是,当然唯一真正有效的强制转换是(Base*)
或(Derived*)
,或者是继承层次结构中它们之间的任何内容。
我还应该提到,作为void *,您无法删除该对象并运行其析构函数。要删除该对象,您需要将该指针强制转换回它的任何类型,以便编译器知道要调用的析构函数。你可以通过Derived
类的类型为Base*
的指针来解决另一个棘手的棘手问题....如果Base::~Base()
析构函数不是virtual
,如果你删除你的通过在Derived
上调用delete
到该对象的Base*
对象,分配将完全取消分配,但只有对象的Base
部分才会运行析构函数。 ...除非使用virtual
关键字定义析构函数,否则即使只有Derived
,也可以删除Base*
对象。我完全不清楚了吗?