This is a reading note of Item 17 of Scott Meyers' book - Effective Modern C++.
1. C++98
4 special functions
- Default constructor/destructor/copy constructor/copy assignment operator
- Generated when not declared
- Can throw
- Implicitly public, inline and non-virtual
- desrtuctor can be virtual if its base class have virtual destructor
Copy constructor and copy assignment operator
- Their generations are independent
- Declare one does not have any effect on other's generation
- Generated when not declared and needed
Rule of Three
- Declaration of copy constructor, copy assignment and desctrctor
* Either all of three
* Or none of three
2. C++11
4 become 6 - move operations (move constructor and move assignment operator).
Move constructor and move assignment operator:
- Generate them if not declared and needed
- Member-wise move except the static members
- Member-wise move the base class part
- "Member-wise move" does not guarantee "move" the object, It is decided by std::move
* If std::move decided it is a move, then move will take place
* Otherwise move is replaced by copy
- Their generations are not independent
* Declare one prevents the generation of the other
* Motivation behind: member-wise move is not good enough for one, neither is for the other
- Their generations are prohibited by any declaration of copy operation
* Motivation behind: if member-wise copy is not good enough, neither is member-wise move
- Their declaration prohibits the generation of copy operation
* Motivation behind: if member-wise move is not good enough, neither is member-wise copy
Rule of Three remains true in C++11
- The declaration of destructor is bond with the copy operations
- Therefore strong motivation: not generate move operation if user-declared destructor exists
Move operations are generated only if the following three conditions are true:
- No copy operations declaration
- No move operation declaration
- No destructor declaration
This rule may extend to copy operations, because the automatic generation of copy operations for classes that have one of copy operation or destructor declared is deprecated by C++. So for now use "default", referring to C++11 features - Explicitly defaulted/deleted member functions, to explicitly declare copy operations generated by compiler. "default" supports copy operations, move operations, (virtual) destructor and default constructor.
As Scott Meyers points out in the example with generated move operations (no move, copy operations and destructor declared), declaring a destructor later can cause performance penalty. Because declaring a destructor suppresses the generation of move operation, and therefore move operation is replaced by copy operations.
Comparison between C++98 and C++11
- Constructor and destructor exactly same, except destructor default as "noexcept" in C++11. Refer to C++11 Features - noexcept.
- Copy constructor or copy assignment operator: same as C++98 - their generations are independent and do member-wise copy on non-static members. Except in C++11 their generations are prohibited by declaration of move operation and Rule of Three is enforced - its generation is deprecated if any user-defined copy operations or destructor declared.
- Move operations: generated on when 3 conditions are met and do member-wise move on non-static members.
Bibliography:
[1] Scotts Meyer, "Effective Mordern C++", O'REILLY, 2014 First Release
[2] Bjarne Stroustrup, "The C++ Programming Language", C++11, 4th Edition
[3] C++ Reading Club @ IG Group