简体   繁体   中英

Passing the managed object of a unique_ptr by reference to a thread function

I can compile the following code:

void threadFunc(Vec3f *&buffer) {}
...
std::unique_ptr<Vec3f []> buffer(new Vec3f[100]);
Vec3f *b = buffer.get();
std::thread(threadFunc, std::ref(b)).join();

But I can't compile:

std::thread(threadFunc, std::ref(buffer.get())).join();

I get the following error at compile time:

error: use of deleted function ‘void std::ref(const _Tp&&) [with _Tp = Vec3<float>*]’

EDIT: the thread is joined before unique_ptr goes out of scope

What's different between the 2 versions? Can I make the second solution work?

Additionally, it seems better to pass by reference a pointer to the managed object than the unique_ptr by reference itself (the threadFunc only has to modify the content of buffer ). Something like:

void threadFunc(std::unique_ptr<Vec3f []> &ptr) {}
std::thread(threadFunc, std::ref(buffer)).join();

Would this be bad practice? Or is this acceptable as well? It seems to me that if I want to change the content of buffer, this is what I should pass to the thread function, not the unique_ptr itself? Any recommendation would be appreciated.

EDIT 2:

So According to one of the answers below, the second option is not possible because std::ref(buffer.get()) uses some temp object. Though the first version despite what's said should work (I can't see why this would be invalid):

Vec3f *tmp = new Vec3f[100];
std::unique_ptr<Vec3f []> buffer = std::unique_ptr<Vec3f []>(tmp);
Vec3f *b = buffet.get(); // address of b == address of tmp
std::thread(threadFunc, std::ref(b));

same as:

std::thread(threadFunc, std::ref(tmp));

As for the solution provided:

void threadFunc(Vec3f *buffer) { buffer[0] = 0; // invalid }
Vec3f *buffer = new Vec3f[100];
std::thread(threadFunc, buffer);

It seems invalid to me as buffer is passed by value and not by reference, however I need to write to buffer. So it needs to be passed by ref.

If someone could clarify it would be great.

The reason why it doesn't work is because your are trying to get a ref to the temporary object. And you can't do this, because reference_wrapper inside it just has the pointer, and it refuses to hold the pointer to the temporary object. It is likely that the version which compiles is actually wrong, as you are passing a pointer to the managed object, which is probably deleted while in use in other thread (unless the thread is joined before unique_ptr goes out of scope)

By the way, unique_ptr was designed exactly to relieve you from those woes. Just pass unique_ptr by value, and let the other thread manage it's lifetime.

Edit: From our discussion, it seems threads are joined before unique_ptr goes out of scope. If my understanding is right, you do not need to provide unique_ptr to thread function at all. Following is a perfectly fine (pseudo)code:

typedef <your type> type_t;
void handle_func(type_t* ptr);
typedef std::unique_ptr<type_t> ptr_t;

ptr_t ptr(new type_t);
std::thread handler(handle_func, ptr.get());
handler.join();

On a side note, from the snippet above it is not even clear why unique_ptr is needed - as opposed to simply use local variable and pass an address or ref() to it. By I suppose, there are reasons for this I am not aware of :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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