pthread_create混乱

时间:2012-12-08 06:34:36

标签: c++ pthreads

在很多场合,我见过这种情况

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

我真的不明白,我该怎么做呢?

1 个答案:

答案 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*对象。我完全不清楚了吗?