I am trying to understand move semantics and in particular how std::move()
works.
I understood that it's basically a static-cast to an rvalue reference type, but this exercise gets me confused. I have implemented a Node
class following the Rule of Five (I know I could have followed the copy and swap idiom for a better implementation).
class Node
{
public:
Node(char data = ' ', Node *left_child = NULL, Node *right_child = NULL) : _data(data), _left_child(left_child), _right_child(right_child)
{
std::cout << "NODE CONSTRUCTOR" << std::endl;
}
Node(const Node& node);
Node(Node&& node) noexcept;
GetData() const;
Node& operator=(const Node &n);
Node& operator=(Node&& node) noexcept;
~Node();
protected:
Node *_left_child;
Node *_right_child;
char _data;
};
char Node::GetData() const
{
return _data;
}
Node::Node(const Node& node)
{
...
}
Node::Node(Node&& node) noexcept
{
std::cout << "MOVE CONSTRUCTOR" << std::endl;
this->_data = node.GetData();
this->_left_child = node._left_child;
this->_right_child = node._right_child;
node._right_child = nullptr;
node._left_child = nullptr;
}
Node& Node::operator=(Node&& node) noexcept
{
std::cout << "MOVE ASSIGNMENT OPERATOR " << std::endl;
if(&node != this)
{
if(this->_right_child != nullptr)
{
delete this->_right_child;
}
if(this->_left_child != nullptr)
{
delete this->_left_child ;
}
}
this->_data = node.GetData();
this->_left_child = node._left_child;
this->_right_child = node._right_child;
node._right_child = nullptr;
node._left_child = nullptr;
return *this;
}
Node::~Node()
{
delete _left_child;
delete _right_child;
}
Node& Node::operator=(const Node &n)
{
...
}
Then in my main()
function:
int main() {
Node *NodeOne = new Node{};
Node NodeTwo{};
std::stack<Node*> stack_of_nodes_ptr;
stack_of_nodes_ptr.push(std::move(NodeOne));
delete stack_of_nodes_ptr.top();
stack_of_nodes_ptr.pop();
std::stack<Node> stack_of_nodes;
stack_of_nodes.push(std::move(NodeTwo));
return 0;
}
The output is:
NODE CONSTRUCTOR
NODE CONSTRUCTOR
CALLING NODE BASE DESTRUCTOR
MOVE CONSTRUCTOR
CALLING NODE BASE DESTRUCTOR
CALLING NODE BASE DESTRUCTOR
My doubt arises seeing that the move constructor is not called in the first push_back()
but only in the second one. The only difference here is that the first stack is of Node*
pointers while the other one is a stack of Node
objects.
Could you please tell me why, in case of raw pointer, move constructor is not called?