-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Move Semantics in POCO
Move semantics were introduced in C++11. It has brought many benefits, but also many hidden subtleties. For an extensive coverage of C++ move semantics, check C++ Move Semantics - The Complete Guide.
Here we discuss the introduction of move semantics to POCO libraries. In particular, how it may affect existing (pre move-semantics) code.
Generally, in regards to the possible state (valid but unspecified), we have two cases after the move operation:
- Objects in a previously existent state (eg.
Poco::AutoPtr
is holding annullptr
pointer after it is moved). - Objects in a new state (eg. Poco::Net::Socket holds a null
pImpl
- a state not existent before move semantics).
Let us say that user wrote a class with default move constructor, which has an AutoPtr
member dereferenced without check for null pointer in the destructor of the class. Prior to AutoPtr
move-semantics introduction, such code worked because AutoPtr
was not movable. After the move semantics introduction, the AutoPtr
member will be null in the moved-from object destructor and cause undefined behavior. This case falls under category 1 above, and it is responsibility of the user to rectify the issue.
A category 2 case has the same effect, but it is different because move operation leaves the moved-from object in a previously nonexistent state. Because a new valid state is introduced with category 2 move semantics, they will not be enabled by default when introduced - such behavior will only be compiled-in when POCO_NEW_STATE_ON_MOVE
is defined to be nonzero.
To rectify the problem, a check for null pointer in destructor is needed prior to invocation. Category 2 movable classes will introduce isNull()
member functions for checking the object internal state.
Move semantics may bring some unpleasant surprises. This short explanation explained the two cases of such surprises, with the solution for avoiding them.