I have a class which is basically a queue used to transfer dynamically allocated objects between 2 threads. The first thread creates the objects and the second one consumes them. I use std::unique_ptr
to pass the objects ownership from thread 1 to thread 2.
Actually calls to the method that put the objects into the queue is like this:
queue.put(std::move(unique_ptr_to_my_object));
and the signature:
bool Queue::put(std::unique_ptr<T> p);
The problem is the put()
method has to check some condition to decide if the object could be added to the queue. In case the condition is false the method simply returns false to indicate it can't add the object to the queue, but the object is destroyed because ownership has already be taken by put()
.
So I wanted to know if it's ok to rewrite put()
like this or if there is a better solution:
bool Queue::put(std::unique_ptr<T> &ref) {
if(CANNOT_ADD)
return false; // ownership remains in the calling function
std::unique_ptr<T> p = std::move(ref); // we know we can add so take ownership
/* ... */
}
Yes, that's fine. The alternative would be:
std::unique_ptr<T> Queue::put(std::unique_ptr<T> p) {
if (CANNOT_ADD)
return p; // Ownership returned to caller.
/* ... */
return {}; // Return empty nullptr to indicate success.
}
Your way has the advantage that the caller retains ownership if the code in ...
throws.
You can change signature of the function to:
std::unique_ptr<T> Queue::put(std::unique_ptr<T> p);
so if that function cannot take that object it would return that pointer back, or nullptr
otherwise. Another solution is to take ownership conditionally:
bool Queue::put(std::unique_ptr<T> &&p);
and move out object only in success. Accepting rvalue reference vs lvalue one is better in this case due to at least 2 reasons:
std::move
explicitly in calling code.Though the fact that you can use that pointer after std::move
make this variant is less readable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With