Module 50
Module 50
L
Partha Pratim
Das
Programming in Modern C++
E
Objectives &
Outlines
Module M50: C++11 and beyond: General Features: Part 5: Rvalue and Move/2
T
Recap
Move Semantics
P
Simple Move
Constructor and
Assignment
Partha Pratim Das
N
Challenges
Solution
std::move
Department of Computer Science and Engineering
Use
Indian Institute of Technology, Kharagpur
Implementation
Project [email protected]
ResMgr Class
MyResource Class
MyClass Class
All url’s in this module have been accessed in September, 2021 and found to be functional
Module Summary
Module M50
L
Partha Pratim
Das
• Understood the difference between Lvalue and Rvalue
E
Objectives &
Outlines • Learnt the advantages of Move in C++ using
T
Recap
◦ Rvalue Reference
Move Semantics
◦ Move Semantics
P
Simple Move
Constructor and
Assignment ◦ Copy / Move Constructor / Assignment
N
Challenges
Solution ◦ Implementation of Move Semantics
std::move
Use
Implementation
Project
ResMgr Class
MyResource Class
MyClass Class
Module Summary
Module M50
L
Partha Pratim
Das
◦ Challenges
E
Objectives &
Outlines ◦ Workaround using std::move
T
Recap • To learn the use and implementation of std::move
Move Semantics
• To put all the pieces together in a project to code move-enabled UDTs
P
Simple Move
Constructor and
Assignment
N
Challenges
Solution
std::move
Use
Implementation
Project
ResMgr Class
MyResource Class
MyClass Class
Module Summary
Module M50
1 Recap of Copy vs. Move and related Concepts
L
Partha Pratim
Das
2 Move Semantics: How to code?
E
Objectives &
Outlines Simple Move Constructor and Assignment
T
Recap Challenges
Move Semantics
Solution
P
Simple Move
Constructor and
Assignment
3 std::move
N
Challenges
Solution Use
std::move
Use
Implementation
Implementation
Project
4 Move Semantics Project
ResMgr Class ResMgr Class
MyResource Class
MyClass Class MyResource Class
Module Summary MyClass Class
5 Module Summary
Programming in Modern C++ Partha Pratim Das M50.4
Recap of Copy vs. Move and related Concepts
Module M50
L
Partha Pratim
Das
E
Objectives &
Outlines
T
Recap
Move Semantics
P
Simple Move
Constructor and
Assignment
N
Challenges
Solution
std::move
Use
Implementation
Project
ResMgr Class Recap of Copy vs. Move and related Concepts
MyResource Class
MyClass Class
Sources:
Module Summary
• Module 49: C++11 and beyond: General Features: Part 4: Rvalue and Move/1
• An Overview of the New C++ (C++11/14), Scott Meyers Training Courses
• Scott Meyers on C++
Programming in Modern C++ Partha Pratim Das M50.5
Copying vs. Moving: Recap (Module 49)
Module M50
L
Partha Pratim
Das
◦ Copy constructors, Copy assignment operators
E
Objectives &
Outlines • C++11 adds support for requests to Move object state for performance improvement.
T
Recap Examples show the benefits of Move in several contexts including:
Move Semantics
◦ Return by value from functions
P
Simple Move
Constructor and
Assignment ◦ Appending to a full vector
N
Challenges
Solution
◦ Swapping two variables
std::move ◦ Choice of Swallow Copy in place of Deep Copy when possible
Use
Implementation
◦ ...
Project • C++11 adds the following for related optimization
ResMgr Class
MyResource Class ◦ Rvalue Reference
MyClass Class
◦ Move Semantics through Move constructors, Move assignment operators
Module Summary
Module M50
L
Partha Pratim
Das
◦ In C, Expressions on left-hand-side (LHS) of an assignment
E
Objectives &
Outlines ◦ Named objects - variables
◦ Legal to apply address of (&) operator
T
Recap
P
Simple Move
Constructor and
Assignment
• Rvalues are generally things we cannot take the address of:
◦ In C, Expressions on right-hand-side (RHS) of an assignment
N
Challenges
Solution
std::move ◦ Unnamed (temporary) objects - expressions, return by value from functions, etc.
Use ◦ Rvalue references (T&&) identify objects that may be moved from
Implementation
Module M50
L
Partha Pratim
Das
E
Objectives &
Outlines
T
Recap
Move Semantics
P
Simple Move
Constructor and
Assignment
N
Challenges
Solution
std::move
Use
Implementation
Project
ResMgr Class Move Semantics: How to code?
MyResource Class
MyClass Class
Sources:
Module Summary
• An Overview of the New C++ (C++11/14), Scott Meyers Training Courses
• Scott Meyers on C++
Module M50
• Move operations take source’s value, may change the source, but leave the source in
valid state:
L
Partha Pratim
Das
E
Objectives & class MyResource { // Representative resource class with move support
Outlines
char *str = nullptr; // Resource pointer
T
Recap
public:
Move Semantics // Move: Constructs by moving resource from rvalue reference source (rr)
P
Simple Move
Constructor and MyResource(MyResource&& rr) noexcept : str(rr.str) // Take the value of source rr
Assignment
{ rr.str = nullptr; } // Changed but valid state set for the source
N
Challenges
Solution
std::move
// Move: Assigns by moving resource from rvalue reference source (rr)
Use MyResource& operator=(MyResource&& rr) noexcept {
Implementation delete [] str; // Release the current value
Project str = rr.str; // Take the value of source rr
ResMgr Class rr.str = nullptr; // Changed but Valid state set for the source
MyResource Class
return *this; // Return the assigned object
MyClass Class
}
Module Summary
...
• Easy for built-in types like pointers above. Gets tricky for UDTs
Programming in Modern C++ Partha Pratim Das M50.9
Move Semantics: How to code?
Module M50
• Like Copy Assignment, MyResource’s move operator= may fail for move-to-self:
L
Partha Pratim
Das
MyResource r;
E
Objectives & r = std::move(r); // undefined behavior! std::move changes r to an rvalue reference
Outlines
... // std::move will be discussed later in this module
T
Recap
P
Simple Move
Constructor and
...
Assignment
*p1 = std::move(*p2); // undefined if p1 == p2
N
Challenges
Solution
Project
MyResource& MyResource&::operator=(MyResource&& rr) noexcept {
ResMgr Class if (this != &rr) {
MyResource Class ... // Do the move as above
MyClass Class
}
Module Summary // else assert(this != &rr); // un-comment to disallow move-to-self
return *this;
}
Programming in Modern C++ Partha Pratim Das M50.10
Move Semantics: How to code?
Module M50 • Next let us attempt to build a move-enabled MyClass that use an object of
MyResource as a resource data member:
L
Partha Pratim
Das
class MyClass { MyResource mRrc; // Resource object
E
Objectives & public:
Outlines
MyClass(MyClass&& c) noexcept : // Move Constructor
T
Recap mRrc(c.mRrc) // Compiles, but actually copies using MyResource(MyResource&)
Move Semantics { ... }
P
Simple Move
Constructor and
MyClass& operator=(MyClass&& c) noexcept { // Move Assignment
Assignment if (this != &c)
N
Challenges
Solution
{ mRrc = c.mRrc; } // Compiles, but actually copies using
return *this; // MyResource::operator=(MyResource&)
std::move
Use
}
Implementation ...
Project };
ResMgr Class
MyResource Class • c.mRrc is an lvalue, because it has a name
MyClass Class
◦ Lvalue-ness / Rvalue-ness orthogonal to type!
Module Summary
. ints can be lvalues or rvalues, and rvalue references can, too.
◦ mRrc initialized by MyResource’s copy constructor / assignment
Programming in Modern C++ Partha Pratim Das M50.11
Move Semantics: How to code?
Module M50
• Next let us try to extend the design on an inheritance hierarchy where MyClass ISA
L
Partha Pratim
Das
MyClassBase
E
Objectives &
Outlines
class MyClassBase { public:
MyClassBase(const MyClassBase&); // Copy Constructor
T
Recap
MyClassBase(MyClassBase&&) noexcept; // Move Constructor
Move Semantics
...
P
Simple Move
Constructor and };
Assignment
N
Challenges
Solution class MyClass: public MyClassBase { public:
std::move MyClass(MyClass&& c) noexcept // Move Constructor
Use : MyClassBase(c) // Compiles, but actually copies using MyClassBase(MyClassBase&)
Implementation
{ ... }
Project ...
ResMgr Class
};
MyResource Class
MyClass Class
• c is an lvalue, because it has a name
Module Summary
◦ Its declaration as MyClass&& not relevant!
• Similar issue will happen for MyClass::operator=(MyClass&&)
Programming in Modern C++ Partha Pratim Das M50.12
Move Semantics: How to code?
Module M50
• How to solve the problems in the coding of move semantics for UDTs?
• In general, in a UDT, there are two kinds of constituent objects:
L
Partha Pratim
Das
E
Objectives &
Outlines ◦ Base Class part like (MyClassBase&)c // MyClass: public MyClassBase
T
Recap
• While we need to copy or move, we use the constructor or assignment operators of the
Move Semantics
underlying classes:
P
Simple Move
Constructor and
Assignment
◦ Construction: mRrc(c.mRrc) and MyClassBase(c)
N
Challenges
Solution ◦ Assignment: mRrc = c.mRrc and MyClassBase::operator=(c)
std::move
Use
• For copy, we use the copy constructor / assignment operator
Implementation • For move, we need to use the move constructor / assignment operator to optimize
Project resource handling
ResMgr Class
MyResource Class ◦ This means for the above four instances of the respective operators, the sources
MyClass Class
(c.mRrc or c) must be rvalues. But they are available by name as lvalues
Module Summary
• Hence, we need a mechanism to convert an lvalue to an rvalue
• std::move in <utility> provides for this
Programming in Modern C++ Partha Pratim Das M50.13
std::move
Module M50
L
Partha Pratim
Das
E
Objectives &
Outlines
T
Recap
Move Semantics
P
Simple Move
Constructor and
Assignment
N
Challenges
Solution
std::move
Use
Implementation
std::move
Project
ResMgr Class
MyResource Class
Sources:
MyClass Class • An Overview of the New C++ (C++11/14), Scott Meyers Training Courses
Module Summary • Scott Meyers on C++
• Quick Q: What’s the difference between std::move and std::forward?, isocpp.org
• On the Superfluousness of std::move – Scott Meyers, isocpp.org, 2012
• std::move, cppreference.com
Programming in Modern C++ Partha Pratim Das M50.14
Explicit Move Requests
Module M50
• To request a move on an lvalue, use std::move from <utility>:
L
Partha Pratim
Das
class MyClassBase { ... };
E
Objectives & class MyClass: public MyClassBase { public:
Outlines
MyClass(MyClass&& c) noexcept : // Move Constructor
T
Recap
MyClassBase(std::move(c)), // Request Move for base class part
Move Semantics mRrc(std::move(c.mRrc)) // Request Move for data member
P
Simple Move
Constructor and { ... }
Assignment
MyClass& operator=(MyClass&& c) noexcept { // Move Assignment
N
Challenges
Solution
if (this != &c) {
std::move
MyClassBase::operator=(std::move(c)); // Request Move for base class part
Use mRrc = std::move(c.mRrc); // Request Move for data member
Implementation }
Project return *this;
ResMgr Class }
MyResource Class
...
MyClass Class
};
Module Summary
• std::move turns lvalues into rvalues
◦ The overloading rules do the rest
Programming in Modern C++ Partha Pratim Das M50.15
Explicit Move Requests
Module M50
L
Partha Pratim
Das
Consider:
E
Objectives &
Outlines
template<typename It>
T
Recap
void someAlgorithm(It begin, It end) {
Move Semantics // permit move from *begin to temp
P
Simple Move
Constructor and
Assignment
// static_cast version
N
Challenges
Solution auto temp1 = static_cast<typename std::iterator_traits<It>::value_type&&>(*begin);
std::move
Use // C-style cast version
Implementation auto temp2 = (typename std::iterator_traits<It>::value_type&&)*begin;
Project
ResMgr Class // std::move version
MyResource Class
MyClass Class
auto temp3 = std::move(*begin);
Module Summary
...
• Great convenience by using std::move
Module M50
• In C++03, given
L
Partha Pratim template<typename T> void f(T& param);
Das
int x;
E
Objectives & f<int&>(x); // T is int&
Outlines
• f is initially instantiated as
T
Recap
Move Semantics
void f(int& & param); // reference to reference
• C++03’s reference-collapsing rule says
P
Simple Move
Constructor and
Assignment
◦ T& & => T&
N
Challenges
Solution • So, after reference collapsing, f’s instantiation is actually: void f(int& param);
std::move • C++11’s rules take rvalue references into account:
Use
Implementation
◦ T& & => T& // from C++03
◦ T&& & => T& // new for C++11
Project
ResMgr Class
◦ T& && => T& // new for C++11
MyResource Class ◦ T&& && => T&& // new for C++11
MyClass Class
• Summary:
Module Summary
◦ Reference collapsing involving a & is always T&
◦ Reference collapsing involving only && is T&&
Programming in Modern C++ Partha Pratim Das M50.17
std::move: Return Type
Module M50
L
Partha Pratim
Das
E
Objectives & template<typename T>
Outlines
typename std::remove_reference<T>::type&&
T
Recap move(MagicReferenceType obj) noexcept {
Move Semantics return obj;
P
Simple Move
Constructor and
}
Assignment
N
Challenges
Solution ◦ Recall that a T& return type would be an lvalue!
std::move
Use
• Hence:
Implementation
Project int x;
ResMgr Class std::move<int&>(x); // calls remove_reference<int&>::type&& std::move(/*...*/)
MyResource Class
MyClass Class
// => int&& std::move(/*...*/)
Module Summary
Module M50
L
Partha Pratim
Das
• An lvalue reference does not work, because rvalues cannot bind to them:
E
Objectives &
Outlines
TVec createTVec(); // as before
T
Recap
TVec&& std::move(TVec& obj) noexcept; // possible move instantiation
Move Semantics
std::move(createTVec()); // error!
P
Simple Move
Constructor and
Assignment
• An rvalue reference does not, either, as lvalues cannot bind to them:
N
Challenges
Solution
Module M50
L
Partha Pratim
Das
E
Objectives & template<typename T>
Outlines
typename std::remove_reference<T>::type&&
T
Recap move(T& lvalue) noexcept {
Move Semantics return static_cast<std::remove_reference<T>::type&&>(lvalue);
P
Simple Move
Constructor and
}
Assignment template<typename T>
N
Challenges
Solution
typename std::remove_reference<T>::type&&
move(T&& rvalue) noexcept {
std::move
Use
return static_cast<std::remove_reference<T>::type&&>(rvalue);
Implementation }
Project
ResMgr Class
• But the perfect forwarding problem1 would remain:
MyResource Class
MyClass Class
◦ To forward n arguments to another function we would need 2n overloads!
Module Summary • Rvalue references aimed at both std::move and perfect forwarding
Module M50
• Given
L
Partha Pratim
Das
template<typename T> void f(T&& param); // note non-const rvalue reference
E
Objectives &
Outlines
T
Recap • T’s deduced type depends on what is passed to param:
Move Semantics
◦ Lvalue ⇒ T is an lvalue reference (T&)
P
Simple Move
Constructor and
Assignment ◦ Rvalue ⇒ T is a non-reference (T)
N
Challenges
Solution • In conjunction with reference collapsing:
std::move
Use int x;
Implementation
f(x); // lvalue: generates f<int&>(int& &&), calls f<int&>(int&)
Project
f(10); // rvalue: generates/calls f<int>(int&&)
ResMgr Class
MyResource Class
MyClass Class TVec vt; // typedef vector<int> TVec;
Module Summary // TVec createTVec();
f(vt); // lvalue: generates f<TVec&>(TVec& &&), calls f<TVec&>(TVec&)
f(createTVec()); // rvalue: generates/calls f<TVec>(TVec&&)
Programming in Modern C++ Partha Pratim Das M50.21
std::move: Implementation
Module M50
• std::move’s parameter is thus T&&:
L
Partha Pratim template<typename T>
Das
typename std::remove_reference<T>::type&&
E
Objectives & move(T&& obj) noexcept {
Outlines
return obj;
T
Recap }
Move Semantics
• This is almost correct. Problem:
P
Simple Move
Constructor and
Assignment ◦ obj is an lvalue (It has a name)
N
Challenges
Solution ◦ move’s return type is an rvalue reference
std::move ◦ Lvalues cannot bind to rvalue references
Use
Implementation • A cast eliminates the problem to give a correct implementation
Project template<typename T>
ResMgr Class typename std::remove_reference<T>::type&&
MyResource Class
MyClass Class
move(T&& obj) noexcept {
using ReturnType = typename std::remove_reference<T>::type&&;
Module Summary
return static_cast<ReturnType>(obj);
}
Module M50
L
Partha Pratim
Das
E
Objectives & template<typename T> // conceptual
Outlines
T&&
T
Recap move(MagicReferenceType obj) noexcept;
Move Semantics
P
Simple Move
Constructor and
template<typename T> // actual
Assignment typename std::remove_reference<T>::type&&
N
Challenges
Solution
move(T&& obj) noexcept;
std::move
Use
• T&& really is a magic2 reference type!
Implementation
Project ◦ For lvalue arguments, T&& becomes T& => lvalues can bind
ResMgr Class
MyResource Class
◦ For rvalue arguments, T&& remains T&& => rvalues can bind
MyClass Class ◦ For const/volatile arguments, const/volatile becomes part of T
Module Summary ◦ T&& parameters can bind anything
Module M50
L
Partha Pratim
Das
E
Objectives &
Outlines
T
Recap
Move Semantics
P
Simple Move
Constructor and
Assignment
N
Challenges
Solution
std::move
Use
Implementation
Project
ResMgr Class Move Semantics Project
MyResource Class
MyClass Class
Module Summary
Module M50 • To put the pieces of the Move Semantics puzzle together, we present a complete project with
classes having resources of POD3 and UDT
L
Partha Pratim
Das
• We also code a resource management helper class (ResMgr) to track the objects (resources)
E
Objectives &
Outlines
created and released dynamically. This will help us to quantify the benefits of move over copy
• All functions are tracked with messages to understand object lifetimes under copy and move
T
Recap
Move Semantics • Using ResMgr, we present applications to compare the performance of the Copy & Move
P
Simple Move
Constructor and
Assignment
version of the classes against the Copy Only version
• The classes are (skeletons of MyResource and MyClass used earlier in the module):
N
Challenges
Solution
std::move
◦ ResMgr: Resource Management Helper Class. It has static member functions to Create(),
Use Release() resources and print statistics (Stat())
Implementation
◦ MyResource: Resource Class with POD resource (char*). It has usual class members,
Project
ResMgr Class
overloaded output operator and a global function to call and return by value
MyResource Class ◦ MyClass: Resource Class with UDT resource (MyResource). It has usual class members,
MyClass Class
overloaded output operator and a global function to call and return by value
Module Summary
• The codes may be used to code move semantics in any project you develop
3 Plain Old Data (POD) refers to built-in types
Programming in Modern C++ Partha Pratim Das M50.25
Move Semantics: ResMgr: Resource Management Helper Class
L
Partha Pratim
Das using namespace std;
E
Objectives & class ResMgr { // Resource Management class to track creation and release of resources
Outlines
static unsigned int nCreated, nReleased; // Counters for created & released resources
T
Recap public:
Move Semantics
ResMgr() { } // Constructor to be called before main
~ResMgr() { // Destructor to be called after main
P
Simple Move
Constructor and cout << "\n\nResources Created = " << nCreated << endl;
Assignment
cout << "Resources Released = " << nReleased << endl;
N
Challenges
}
Solution
inline static char *Create(const char *s) // Create a resource from s
std::move { return (s) ? ++nCreated, strdup(s) : nullptr; } // If s is not null, copy & increment counter
Use
inline static void Release(char *s) // Release the resource held by s
Implementation
{ (s) ? free(s), ++nReleased : 0; } // If s is not null, increment counter & free resource
Project inline static void Stat() // Print stats for resources created and released
ResMgr Class { cout << " Stat = (" << nCreated << ", " << nReleased << ")\n\n"; }
MyResource Class };
MyClass Class unsigned int ResMgr::nCreated = 0; // Define and initialize Counters
Module Summary unsigned int ResMgr::nReleased = 0;
Module M50
class MyResource { // Representative resource class with copy-only support
L
Partha Pratim
Das
char *str = nullptr; // Resource pointer
public:
E
Objectives & MyResource(const char* s = nullptr) : str(ResMgr::Create(s)) // Param. & Defa. Ctor
Outlines { cout << "Ctor[R] "; } // Creates resource
MyResource(const MyResource& s) : str(ResMgr::Create(s.str)) // Copy Ctor
T
Recap
{ cout << "C-Ctor[R] "; } // Copy-Creates resource
Move Semantics MyResource& operator=(const MyResource& s) { cout << "C=[R] "; // Copy Assignment
P
Simple Move
Constructor and
if (this != &s) { ResMgr::Release(str); str = ResMgr::Create(s.str); }
Assignment return *this; // Releases and Copy-Creates resource
}
N
Challenges
Solution
~MyResource() // Destructor
std::move { cout << "Dtor[R] "; ResMgr::Release(str); } // Releases resource
Use friend ostream& operator<<(ostream& os, const MyResource& s) { // Streams resource value
Implementation cout << ((s.str) ? s.str : "null"); return os; // Streams "null" for nullptr (no resource)
Project }
ResMgr Class };
MyResource Class
MyClass Class MyResource f(MyResource s) // Global function
Module Summary
{ cout << "f[R] "; return s; } // Uses call-by-value & return-by-value
L
Partha Pratim
Das
MyResource r1{ "ppd" }; // Ctor[R] r1=ppd Stat = (1, 0)
cout << "r1=" << r1; ResMgr::Stat(); // r1 constructed with parameter
E
Objectives &
Outlines MyResource r2{ r1 }; // C-Ctor[R] r2=ppd r1=ppd Stat = (2, 0)
cout << "r2=" << r2 << " r1=" << r1; ResMgr::Stat(); // r2 copy constructed from r1
T
Recap
Move Semantics MyResource r3{ f(r2) }; // C-Ctor[R] f[R] C-Ctor[R] Dtor[R] r3=ppd r2=ppd Stat = (4, 1)
P
Simple Move
Constructor and
cout << "r3=" << r3 << " r2=" << r2; ResMgr::Stat(); // r3 C-Ctor from f(r2): C-Ctor / Dtor for param
Assignment
N
Challenges r1 = r2; // C=[R] r1=ppd r2=ppd Stat = (5, 2)
Solution cout << "r1=" << r1 << " r2=" << r2; ResMgr::Stat(); // r1 copy assigned from r2
std::move
Use MyResource r4; // Ctor[R] r4=null Stat = (5, 2)
Implementation cout << "r4=" << r4; ResMgr::Stat(); // r4 default constructed
Project
ResMgr Class r4 = f(r3); // C-Ctor[R] f[R] C-Ctor[R] C=[R] Dtor[R] Dtor[R] r4=ppd r3=ppd Stat = (8, 4)
MyResource Class cout << "r4=" << r4 << " r3=" << r3; ResMgr::Stat(); // r4 C= from f(r3): trace debug to understand
MyClass Class } // m.~ResMgr is called after the destruction of local automatic objects to print the final statistics
// Dtor[R] Dtor[R] Dtor[R] Dtor[R]
Module Summary
// Resources Created = 8 Resources Released = 8 // printed from m.~ResMgr
• Note that ResMgr m is a global static object that is created before and destroyed after main()
• Track function call messages to understand the lifetimes of object
Programming in Modern C++ Partha Pratim Das M50.28
Move Semantics: MyResource: POD Resource Class
Copy & Move
class MyResource { // Representative resource class with copy-and-move support
Module M50
char *str = nullptr; // Resource pointer
public:
L
Partha Pratim
Das MyResource(const char* s = nullptr) : str(ResMgr::Create(s)) // Param. & Defa. Ctor
{ cout << "Ctor[R] "; } // Creates resource
E
Objectives &
Outlines
MyResource(const MyResource& s) : str(ResMgr::Create(s.str)) // Copy Ctor
{ cout << "C-Ctor[R] "; } // Copy-Creates resource
T
Recap MyResource(MyResource&& s) noexcept : str(s.str) // Move Ctor
Move Semantics { cout << "M-Ctor[R] "; s.str = nullptr; } // Moves resource
P
Simple Move MyResource& operator=(const MyResource& s) { cout << "C=[R] "; // Copy Assignment
Constructor and
Assignment
if (this != &s) { ResMgr::Release(str); str = ResMgr::Create(s.str); }
return *this; // Releases and Copy-Creates resource
N
Challenges
Solution }
MyResource& operator=(MyResource&& s) noexcept { cout << "M=[R] "; // Move Assignment
std::move
if (this != &s) { ResMgr::Release(str); str = s.str; s.str = nullptr; }
Use
Implementation
return *this; // Releases and Moves resource
}
Project
~MyResource() // Destructor
ResMgr Class
{ cout << "Dtor[R] "; ResMgr::Release(str); } // Releases resource
MyResource Class
friend ostream& operator<<(ostream& os, const MyResource& s) { // Streams resource value
MyClass Class
cout << ((s.str) ? s.str : "null"); return os; // Streams "null" for nullptr (no resource)
Module Summary }
};
MyResource f(MyResource s) // Global function
{ cout << "f[R] "; return s; } // Uses call-by-value & return-by-value
Programming in Modern C++ Partha Pratim Das M50.29
Move Semantics: Application using Copy & Move MyResource
Module M50 int main() { // Application to check resource behavior for copy-and-move support through
// copy construction / assignment and move construction / assignment
L
Partha Pratim
Das
MyResource r1{ "ppd" }; // Ctor[R] r1=ppd Stat = (1, 0)
cout << "r1=" << r1; ResMgr::Stat();
E
Objectives &
Outlines MyResource r2{ r1 }; // C-Ctor[R] r2=ppd r1=ppd Stat = (2, 0)
cout << "r2=" << r2 << " r1=" << r1; ResMgr::Stat();
T
Recap
Move Semantics MyResource r3{ f(r2) }; // C-Ctor[R] f[R] M-Ctor[R] Dtor[R] r3=ppd r2=ppd Stat = (3, 0)
P
Simple Move
Constructor and
cout << "r3=" << r3 << " r2=" << r2; ResMgr::Stat(); // r3 M-Ctor from f(r2): C-Ctor / Dtor for param
Assignment
N
Challenges r1 = r2; // C=[R] r1=ppd r2=ppd Stat = (4, 1)
Solution cout << "r1=" << r1 << " r2=" << r2; ResMgr::Stat();
std::move
Use MyResource r4; // Ctor[R] r4=null Stat = (4, 1)
Implementation cout << "r4=" << r4; ResMgr::Stat();
Project
ResMgr Class r4 = f(r3); // C-Ctor[R] f[R] M-Ctor[R] M=[R] Dtor[R] Dtor[R] r4=ppd r3=ppd Stat = (5, 1)
MyResource Class cout << "r4=" << r4 << " r3=" << r3; ResMgr::Stat(); // r4 M= from f(r3): Note M-Ctor in f(r3)
MyClass Class }
// Dtor[R] Dtor[R] Dtor[R] Dtor[R]
Module Summary
// Resources Created = 5 Resources Released = 5
• Compared to copy-only, we created and released (8 – 5) = 3 resources less with copy-and-move
Programming in Modern C++ Partha Pratim Das M50.30
Move Semantics: MyClass: UDT Resource Class - Copy & Move
(broken!)
Module M50 class MyClass { MyResource mRrc; // Resource object
public:
L
Partha Pratim
Das
MyClass() : mRrc("") // Defa. Ctor
{ cout << "D-Ctor[C] "; }
MyClass(const MyResource& r) : mRrc(r) // Param. Ctor
E
Objectives &
Outlines { cout << "Ctor[C] "; }
MyClass(const MyClass& c) : mRrc(c.mRrc) // Copy Ctor
T
Recap
{ cout << "C-Ctor[C] "; }
Move Semantics MyClass(MyClass&& c) noexcept : mRrc(c.mRrc) // Move Ctor
P
Simple Move
Constructor and
{ cout << "M-Ctor[C] "; }
Assignment MyClass& operator=(const MyClass& c) { cout << "C=[C] "; // Copy Assignment
if (this != &c) { mRrc = c.mRrc; }
N
Challenges
Solution return *this;
std::move }
Use MyClass& operator=(MyClass&& c) noexcept { cout << "M=[C] "; // Move Assignment
Implementation if (this != &c) { mRrc = c.mRrc; }
Project
return *this;
ResMgr Class }
MyResource Class ~MyClass() /* Destructor */ { cout << "Dtor[C] "; }
MyClass Class friend ostream& operator<<(ostream& os, const MyClass& c) // Streams resource value
{ cout << c.mRrc; return os; }
Module Summary
};
MyClass f(MyClass s) // Global function
{ cout << "f[C] "; return s; } // Uses call-by-value & return-by-value
Programming in Modern C++ Partha Pratim Das M50.31
Move Semantics: Application using Copy & Move MyClass
Module M50
int main() {
L
Partha Pratim
Das
MyResource r1{ "ppd" }; // Ctor[R] r1=ppd Stat = (1, 0)
cout << "r1=" << r1; ResMgr::Stat();
E
Objectives &
Outlines MyClass c1{ r1 }; // C-Ctor[R] Ctor[C] c1=ppd Stat = (2, 0)
cout << "c1=" << c1; ResMgr::Stat();
T
Recap
Move Semantics MyClass c2{ f(c1) }; // C-Ctor[R] C-Ctor[C] f[C] C-Ctor[R] M-Ctor[C] Dtor[C] Dtor[R]
P
Simple Move
Constructor and
// c2=ppd c1=ppd Stat = (4, 1)
Assignment // c2 C-Ctor[C] from f(c1). Calls M-Ctor[C] yet copies resource
N
Challenges cout << "c2=" << c2 << " c1=" << c1; ResMgr::Stat();
Solution
L
Partha Pratim
Das MyClass() : mRrc("") // Defa. Ctor
{ cout << "D-Ctor[C] "; }
E
Objectives & MyClass(const MyResource& r) : mRrc(r) // Param. Ctor
Outlines
{ cout << "Ctor[C] "; }
T
Recap MyClass(const MyClass& c) : mRrc(c.mRrc) // Copy Ctor
Move Semantics
{ cout << "C-Ctor[C] "; }
MyClass(MyClass&& c) noexcept : mRrc(std::move(c.mRrc)) // Move Ctor
P
Simple Move
Constructor and { cout << "M-Ctor[C] "; }
Assignment
MyClass& operator=(const MyClass& c) { cout << "C=[C] "; // Copy Assignment
N
Challenges
if (this != &c) { mRrc = c.mRrc; }
Solution
return *this;
std::move }
Use
MyClass& operator=(MyClass&& c) noexcept { cout << "M=[C] "; // Move Assignment
Implementation
if (this != &c) { mRrc = std::move(c.mRrc); }
Project return *this;
ResMgr Class }
MyResource Class ~MyClass() /* Destructor */ { cout << "Dtor[C] "; }
MyClass Class friend ostream& operator<<(ostream& os, const MyClass& c) // Streams resource value
Module Summary { cout << c.mRrc; return os; }
};
MyClass f(MyClass s) // Global function
{ cout << "f[C] "; return s; } // Uses call-by-value & return-by-value
Programming in Modern C++ Partha Pratim Das M50.33
Move Semantics: Application using Copy & Move MyClass
L
Partha Pratim
Das cout << "r1=" << r1; ResMgr::Stat();
E
Objectives & MyClass c1{ r1 }; // C-Ctor[R] Ctor[C] c1=ppd Stat = (2, 0)
Outlines
cout << "c1=" << c1; ResMgr::Stat();
T
Recap
Move Semantics
MyClass c2{ f(c1) }; // C-Ctor[R] C-Ctor[C] f[C] M-Ctor[R] M-Ctor[C] Dtor[C] Dtor[R]
// c2=ppd c1=ppd Stat = (3, 0)
P
Simple Move
Constructor and // c2 C-Ctor[C] from f(c1). Calls M-Ctor[C] and does not copy. FIXED
Assignment
cout << "c2=" << c2 << " c1=" << c1; ResMgr::Stat();
N
Challenges
Solution
c1 = f(c2); // C-Ctor[R] C-Ctor[C] f[C] M-Ctor[R] M-Ctor[C] M=[C] M=[R]
std::move // Dtor[C] Dtor[R] Dtor[C] Dtor[R]
Use
// c1=ppd c2=ppd Stat = (4, 1)
Implementation
// c1 C=[C] from f(c2). Calls M-Ctor[C] and does not copy. FIXED
Project cout << "c1=" << c1 << " c2=" << c2; ResMgr::Stat();
ResMgr Class }
MyResource Class // Dtor[C] Dtor[R] Dtor[C] Dtor[R] Dtor[R]
MyClass Class // Resources Created = 4 Resources Released = 4
Module Summary
Module M50
L
Partha Pratim
Das
• Understood the use and implementation of std::move
E
Objectives &
Outlines • Studied a project to code move-enabled UDTs
T
Recap
Move Semantics
P
Simple Move
Constructor and
Assignment
N
Challenges
Solution
std::move
Use
Implementation
Project
ResMgr Class
MyResource Class
MyClass Class
Module Summary