简体   繁体   English

pthread_create混乱

[英]pthread_create confusion

In many occasions I have seen this situation 在很多情况下我都看到这种情况

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

First, is that proper C++ code? 首先,那是正确的C ++代码吗? or am I missing something? 还是我错过了什么? I have done some readings and apparently casting a pointer to class to a void* causes loss of information and calling getname() on the derived class can be illegal. 我做了一些阅读,显然将指向类的指针强制转换为void *会导致信息丢失,并且在派生类上调用getname()可能是非法的。

What they suggest if I understood correctly is something like this: 如果我正确理解,他们的建议是这样的:

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

I don't get it really, how do I need to this properly? 我真的不明白,我该如何正确处理?

Oh, wow... No, your 2nd example leaks the memory allocated by malloc(), and from the comment, if you follow that advice, you'll be free()'ing your new Derived() allocation in ThreadFun when you think you're freeing the malloc() allocation. 哦,哇...不,您的第二个示例泄漏了malloc()分配的内存,并且从注释中,如果您遵循该建议,当您执行new Derived()分配时,您将在ThreadFun中释放()认为您正在释放malloc()分配。

With regard to casting a pointer to a class to void* causing a loss of information.... It doesn't. 关于将指向类的指针强制转换为void *会导致信息丢失....并非如此。 Plain & simple. 简单明了。 What it loses is the compiler's understanding of what that pointer means. 它失去的是编译器对该指针含义的理解。 If you know what it means, you can always cast it back to its proper type & get its full functionality back, which is exactly what the first example does. 如果知道它的含义,则始终可以将其转换回其正确的类型并获得其完整的功能,这正是第一个示例所做的。 When the ThreadFun() function starts in the new thread, it casts the void* back to its original type, which is Derived*. 当ThreadFun()函数在新线程中启动时,它将void *强制转换回其原始类型,即Derived *。

I'm noticing that when you initially called for the new Derived() allocation, you assigned the return pointer to a pointer of type Base* . 我注意到,当您最初调用new Derived()分配时,您将返回指针分配给了Base*类型的指针。 I'm assuming class Derived inherits from class Base , so the assignment there actually causes a "loss of information" from the standpoint that while it's a pointer of type Base* you lose any non-polymorphic behavior of the Derived class. 我假设class Derived继承自class Base ,因此从它的角度出发,它实际上是一种“信息丢失”,尽管它是Base*类型的指针,但您会失去Derived类的任何非多态行为。 But by the time you cast it back to its real type in ThreadFun(), it regains its full functionality. 但是,当您在ThreadFun()中将其强制转换回其实际类型时,它重新获得了全部功能。 Note that if instead you allocated a new Base object and started up your new thread with that, and in ThreadFun() you casted that to a Derived* , the compiler would let you do that, but you'd have undefined behavior... probably a crash. 请注意,如果改为分配一个new Base对象并以此启动新线程,然后在ThreadFun()中将其强制转换为Derived* ,则编译器将允许您执行此操作,但是您将具有未定义的行为...可能是崩溃。 Because (due to the pthreads interface) you have to go through a void*, there's no type-checking safety to be had, even with C++ style casts. 因为(由于pthreads接口)您必须经历一个void *,所以即使使用C ++样式转换,也没有类型检查的安全性。 So you could convert that void* to anything you wanted, and the compiler would let you. 因此,您可以将void *转换为所需的任何内容,然后编译器将允许您进行操作。 But of course the only truly valid casts are either (Base*) or (Derived*) , or anything in between them in the inheritance hierarchy. 但是当然,唯一真正有效的强制转换是(Base*)(Derived*) ,或者是继承层次结构中介于两者之间的任何内容。

I should also mention that as a void*, you can't delete the object and have its destructor run. 我还应该提到,作为void *,您不能删除对象并运行其析构函数。 To delete the object, you need to cast that pointer back to whatever type it is in order for the compiler to know what destructor to call. 要删除该对象,您需要将该指针强制转换回任何类型,以便编译器知道要调用的析构函数。 There's another tricky sticky situation you can get into with pointers to Derived classes being of type Base* .... If the Base::~Base() destructor is NOT virtual , if you delete your Derived object by calling delete on a Base* to that object, the allocation will be fully deallocated, but only the Base portion of the object will have its destructor run..... UNLESS the destructors were defined with the virtual keyword, which allows you to delete a Derived object even with only a Base* to it. 还有一种棘手的棘手情况,您可以使用指向类型为Base* ...的Derived类的指针。如果Base::~Base()析构函数不是virtual ,则可以通过在Base*上调用delete来删除Derived对象对于该对象,分配将被完全取消分配,但是只有对象的Base部分将运行其析构函数。....除非用virtual关键字定义了析构函数,否则即使仅使用virtual关键字也可以删除Derived对象一个Base* Have I made myself perfectly unclear? 我是否让自己完全不清楚?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM