No matching function for call to pthread_create Ob

2019-03-05 04:25发布

问题:

converting my project to ARC but says it can't due to the following error 'No matching function for call to pthread_create'. Here is the code it falls in, happens specifically on the line starting with pthread create. How can I fix this? It also says Candidate function not viable: no known conversion from 'NSString *' to 'void * _Nullable' for 4th argument in the sidebar underneath the error.

I've cut off the rest of the function but can provide more detail if necessary.

void World::loadWorld(std::string name)
{
    if(doneLoading==0)
    {
    doneLoading=1;
    Resources::getResources->stopMenuTune();
    if(LOW_MEM_DEVICE)
    {
        menu->deactivate();

        Resources::getResources->unloadMenuTextures();
        terrain->allocateMemory();
        terrain->loadTerrain(name,TRUE);
        doneLoading=2;
        hud->fade_out=1;
    }
    else
    {
        terrain->allocateMemory();
        pthread_t foo;
        pthread_create(&foo,NULL,loadWorldThread, nsstring(name));
    }
}

回答1:

As your error message indicates the 4th argument to pthread_create is of type void *. Under ARC you cannot simply pass an Obj-C object reference as a void * as ARC would is not able to track the reference once it is stored in a C(++) pointer variable, and therefore cannot manage the object's memory.

For situations where an Obj-C reference must be passed into the C(++) world a bridge cast can be used to inform ARC how the memory should be managed. However in your case there a better way, just pass the C++ pointer, name, without creating an NSString. If loadWorldThread expects a std::string that is the correct thing to do anyway. If it expects an NSString * then either:

  • modify it to take a std::string and do any required conversion to NSString * within it; or

  • write a small intermediate function which takes a std::string, produces an NSString * from it, and then calls loadWorldThread. Pass this new function to pthread_create.

Doing either of the above avoids the use of a bridge cast in the pthread_create call to move the Obj-C reference into the C(++) world and out of ARC control; and another bridge cast in loadWorldThread (or intermediate function as above) to move it back into the Obj-C world and into ARC control.

Addendum

Expanding on the last paragraph, as the method there seems better suited to your situation. First, it is assumed that your code:

nsstring(name)

takes a value of type std::string and returns a value of type NSString, if it does not then look up how to do this conversion.

After the above expression you have a reference to an NSString under ARC control. You cannot simply pass such a reference as a void *, you must take it out of ARC's control first and take responsibility for its memory management (but not for long as you will see). You can bridge cast your NSString * to a CFStringRef:

CFStringRef cfName = (__bridge_retain CFStringRef)nsstring(name);

You can now pass cfName, which is a reference to a heap-allocated CFString, as a void *.

Now in loadWorldThread; which should be declared to take a void *, something like void loadWorldThread(void *arg) { ... }; you need to bridge cast your CFStringRef back to NSString * and hands responsibility for its memory management back to ARC:

NSString *nsName = (__bridge_transfer NSString *)arg;

The above is a standard pattern to pass an ARC controlled reference though an anonymous reference (void *).

(Note: the above uses CFStringRef to make it clear that you are passing around a reference to a manually managed CFString, you can cast directly to void * and back again, indeed you will notice that when casting back arg was not first cast to a CFStringRef to demonstrate this.)

HTH