Template<typename t>classqueue{Private: structNode {T data; Std::unique_ptr<T> next =nullptr; Node (T _data): Data (Std::move (_data)) {}}; Std::unique_ptr<Node> head =nullptr; Node* Tail =nullptr; Public: Queue ()=default; Queue (Constqueue&) =Delete; Queue&operator=(Constqueue&) =Delete; Std::shared_ptr<T>Trypop () {if(Head = =nullptr) { returnStd::shared_ptr<t>(); } AutoConstresult = Std::make_shared<t> (Std::move (head->data)); AutoConstOldhead =Std::move (head); Head= Std::move (oldhead->next); returnresult; } voidpush (T newval) {Auto Newnextnode= std::make_unique<node>(Std::move (newval)); Auto Newtail= Newnextnode.Get (); if(Tail! =nullptr) {Tail->next =Std::move (Newnextnode); } Else{Head=Std::move (Newnextnode); } Tail=Newtail; }};
I have also wondered why the tail was not used as a unique_ptr, so a counter-act was employed. If the type of tail is a unique_ptr, then when you push a new value, the next action should be:
Auto Newtail = make_unique<t>(newvalue); tail->next == Move (Newtail); oops!
The problem is on the third line. How to say, if it is copy semantics, then it is true, but the use of move, so after the first move operation, Newtail will be destructor, the second move is a nullptr.
Of course, if you use bare pointers all the same:
New // new node tail->next = Newtail; // new node becomes now tail next tail = newtail; // let tail point to the real new node
Has achieved the effect, but the release of its resources has become a tricky issue, so it makes sense to set the type of head and tail to unique_ptr and node*. When adding an element, in order to save the information of the new node, a unique_ptr is constructed based on the added value to replace the previous tail's next, and since the unique_ptr is destroyed by using move, it is necessary to get the new chain by using get before replacing it. Table node information then at the end let tail point to the real team tail.
Very simple single-threaded queue