Below is queue example in "C++ concurrency in action 2nd". This example is single threaded queue, which will be modified to explain thread safe.
template<typename T>
class queue {
private:
struct node {
T data;
std::unique_ptr<node> next;
node(T data_) : data(std::move(data_)) {}
};
std::unique_ptr<node> head;
node* tail;
public:
queue() : tail(nullptr) {};
queue(const queue& other) = delete;
queue& operator=(const queue& other) = delete;
std::shared_ptr<T> try_pop() {
if (!head) return std::shared_ptr<T>();
std::shared_ptr<T> const res(std::make_shared<T>(std::move(head->data)));
std::unique_ptr<node> const old_head = std::move(head);
head = std::move(old_head->next);
if(!head) tail = nullptr;
return res;
}
void push(T new_value) {
std::unique_ptr<node> p(new node(std::move(new_value)));
node* const new_tail = p.get();
if(tail) {
tail->next = std::move(p);
} else {
head = std::move(p);
}
tail = new_tail;
}
};
I can understand this queue works fine, but the way try_pop() is implemented seems to be weird. Is it better way to do like below ?
std::shared_ptr<T> try_pop() {
if (!head) return std::shared_ptr<T>();
std::shared_ptr<T> const res(std::make_shared<T>(std::move(head->data)));
// std::unique_ptr<node> const old_head = std::move(head);
// head = std::move(old_head->next);
head = std::move(head->next);
if(!head) tail = nullptr;
return res;
}
Why head should be copied to old_head on this? Is there any reason I missed?