Copy Control Part II Review copy control consists

  • Slides: 7
Download presentation
Copy Control (Part II) • Review: copy control consists of 5 distinct operations –

Copy Control (Part II) • Review: copy control consists of 5 distinct operations – A copy constructor initializes an object by duplicating the const l-value that was passed to it by reference – A copy-assignment operator (re)sets an object’s value by duplicating the const l-value passed to it by reference – A destructor manages the destruction of an object – A move constructor initializes an object by transferring the implementation from the r-value reference passed to it – A move-assignment operator (re)sets an object’s value by transferring the implementation from the r-value reference passed to it • Today we’ll focus on the last 2 operations and other features (introduced in C++11) like r-value references – I. e. , features that support the new C++11 move semantics CSE 332: C++ copy control II

Motivation for Move Semantics • Copy construction and copy-assignment may be expensive due to

Motivation for Move Semantics • Copy construction and copy-assignment may be expensive due to time/memory for copying • It would be more efficient to simply “take” the implementation from the passed object, if that’s ok • It’s ok if the passed object won’t be used afterward – E. g. , if it was passed by value and so is a temporary object – E. g. , if a special r-value reference says it’s ok to take from (as long as object remains in a state that’s safe to destruct) • Note that some objects require move semantics – I. e. , types that don’t allow copy construction/assignment – E. g. , unique_ptr, ifstream, thread, etc. • New for C++11: r-value references and move function – E. g. , int i; int &&rvri = std: : move(i); CSE 332: C++ copy control II

Synthesized Move Operations • Compiler will only synthesize a move operation if – Class

Synthesized Move Operations • Compiler will only synthesize a move operation if – Class does not declare any copy control operations, and – Every non-static data member of the class can be moved • Members of built-in types can be moved – E. g. , by std: : move etc. • User-defined types that have synthesized/defined version of the specific move operation can be moved • L-values are always copied, r-values can be moved – If there is no move constructor, r-values only can be copied • Can ask for a move operation to be synthesized – I. e. , by using = default – But if cannot move all members, synthesized as = delete CSE 332: C++ copy control II

R-Values, L-Values, and References to Either • A variable is an l-value (has a

R-Values, L-Values, and References to Either • A variable is an l-value (has a location) – E. g. , int i = 7; • Can take a regular (l-value) reference to it – E. g. , int & lvri = i; • An expression is an r-value – E. g. , i * 42 • Can only take an r-value reference to it (note syntax) – E. g. , int && rvriexp = i * 42; • Can only get r-value reference to l-value via move – E. g. , int && rvri = std: : move(i); – Promises that i won’t be used for anything afterward – Also, must be safe to destroy i (could be stack/heap/global) CSE 332: C++ copy control II

Move Constructors • Note r-value reference // takes implementation from a Int. Array: :

Move Constructors • Note r-value reference // takes implementation from a Int. Array: : Int. Array(Int. Array &&a) : size_(a. size_), values_(a. values_) { – Says it’s safe to take a’s implementation from it – Promises only subsequent operation will be destruction • Note constructor design // make a safe to destroy a. values_ = nullptr; a. size_ = 0; } CSE 332: C++ copy control II – A lot like shallow copy constructor’s implementation – Except, zeroes out state of a – No sharing, current object owns the implementation – Object a is now safe to destroy (but is not safe to do anything else with afterward)

Move-Assignment Operators • No allocation, so no exceptions to worry about – Simply free

Move-Assignment Operators • No allocation, so no exceptions to worry about – Simply free existing implementation (delete values_) – Then copy over size and pointer values from a – Then zero out size and pointer in a • This leaves assignment complete, a safe to destroy – Implementation is transferred from a to current object Array & Array: : operator=(Array &&a) { // Note r-value reference if (&a != this) { // still test for self-assignment delete [] values_; // safe to free first (if not self-assigning) size_ = a. size_; // take a’s size values_ = a. values_; // take a’s pointer value a. size_ = 0; // zero out a’s size a. values_ = nullptr; // zero out a’s pointer (now safe to destroy) } return *this; } CSE 332: C++ copy control II

Move Semantics and Inheritance • Base classes should declare/define move operations – If it

Move Semantics and Inheritance • Base classes should declare/define move operations – If it makes sense to do so at all – Derived classes then can focus on moving their members – E. g. , calling Base: : operator= from Derived: : version • Containers further complicate these issues – Containers hold their elements by value – Risks slicing, other inheritance and copy control problems • So, put (smart) pointers, not objects, into containers – Access is polymorphic if destructors, other methods virtual – Smart pointers may help reduce need for copy control operations, or at least simplify cases where needed CSE 332: C++ copy control II