![]() |
engineering training presentations publications blog | ||||||||||||||||||||
home sitemap |
C++: Implementation of Move Construction and Move Assignment | |||||||||||||||||||
c++ embedded c++ embedded linux
|
21-Mar-2015 C++: Implementation of Move Construction and Move AssignmentThomas Becker has a very good article on rvalue references and move semantics. Unfortunately, his article lacks a comprehensive discussion how to implement the move operations. This post tries to fill the gap. ExampleAssume a resource controlling wrapper class around a connection construct provided by a C library. We're interested here only in creating and closing such a connection, and here's the relevant part of the C header: typedef int connection_id; enum { BadConnection = -1 }; connection_id open_connection(char const *connect_str); void close_connection(connection_id con); A simple C++ class wrapper for it looks like this: class Connection { public: Connection(std::string const &conStr) : con(open_connection(conStr.c_str())) { if (con == BadConnection) { throw std::runtime_error ("Connection couldn't be created"); } } ~Connection() { close_connection(con); } // no copy Connection(Connection const &) = delete; Connection &operator=(Connection const &) = delete; // access connection_id get() const { return con; } private: connection_id con; };
The constructor creates the connection, stores it and cares for errors.
The destructor cleans up, and we provide an accessor function. MoveWhile copying is not very useful for
If you think about real things, this becomes obvious:
if you move real matter from one table to the other,
the original space is now empty (actually probably filled by air now).
In our example, if we move from one ~Connection() { closeCon(con); } private: void closeCon(connection_id c) { if (c != BadConnection) { close_connection(c); } } Jens Weller has some more notes on the state of the moved-from object on the Meeting C++ website. Move Constructor
Given the notes above, the move constructor for our Connection(Connection &&other) : con(other.con) { other.con = BadConnection; }
One difference to the copy constructor is that we don't take the
Connection(Connection &&other)
As stated above, we need to modify the
In the member initializer list we take over the data from the
: con(std::move(other.con))
This version also makes it more explicit that we want to move the data.
However, as And finally, in the body, we set the other object to an invalid state. Move AssignmentAssignment is logically the combination of the destruction of the old value and construction of the new one. For move assignment, the construction is done by move construction. So here's the code that combines the actions of the destructor and the move constructor: Connection &operator=(Connection &&other) { if (&other == this) { return *this; } closeCon(con); con = other.con; other.con = BadConnection; return *this; }
Again, we don't take
This is now a perfectly valid implementation and probably as efficient
as it gets.
Maybe you heard at some time that this form of check against self assigment
is not the preferred way to do it, but here (and for now) it's ok.
I'll cover more of move assignment implementation options
(including self-assignment, whether you should mark move operations as
CommentsAny comments, remarks, correction, etc. are welcome. |
Moving |
||||||||||||||||||
home
sitemap
engineering
consulting
coaching
training
presentations
publications
blog
contact
copyright © 2003-2023 vollmann engineering gmbh |