C++ Library Extensions 2022.12.09
To help learn modern C++ programming
020-copy_elision.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2
3/*
4 1. We will first learn what is "Copy Elision."
5
6 2. If we are to use Named Return Value Optimization technique,
7 we have to return the same named instance from all branches in the function.
8
9 Using "Copy Elision" and "Named Return Value Optimization," we can
10 significantly improve the performance of our algorithm.
11
12 Its impact on our algorithm is by no means small.
13
14 3. If a class defines both copy constructor and move constructor, and if
15 we return an instance of that class from a function as pure rvalue or prvalue,
16 the move constructor take precedence over the copy constructor.
17
18 4. C++ compiler generates totally different binary code for debugging build and release build
19 depending on commandline switches.
20
21 Your debugging build successfully works but your release build can fail.
22 So, I almost never use C++ debugger.
23
24*/
27
28class CopyOrMove
29{
30 private:
31 int m_member;
32
33 public:
34
35 void SetValue(int m) { this->m_member = m; }
36
37 CopyOrMove(int m = int{}): m_member{m}
38 {
39 stream << "Default constructor called" << endl;
40 }
41
42 CopyOrMove(const CopyOrMove& right_hand_side):
43 m_member{right_hand_side.m_member}
44 {
45 stream << "Copy constructor called" << endl;
46 }
47
48 CopyOrMove& operator=(const CopyOrMove& right_hand_side)
49 {
50 stream << "Copy assignment operator called"<< endl;
51
52 // I will talk more about std::addressof() function
53 // in some future sessions
54 if(this != std::addressof(right_hand_side))
55 {
56 this->m_member = right_hand_side.m_member;
57 }
58
59 return *this;
60 }
61
62 CopyOrMove(CopyOrMove&& right_hand_side):
63 m_member{ std::move(right_hand_side.m_member) }
64 {
65 stream << "Move constructor called" << endl;
66 }
67
68 CopyOrMove& operator=(CopyOrMove&& right_hand_side)
69 {
70 stream << "Move assignment operator called" << endl;
71 if(this != std::addressof(right_hand_side))
72 {
73 this->m_member = std::move(right_hand_side.m_member);
74 }
75
76 return *this;
77 }
78
80 {
81 stream << "Destructor is called" << endl;
82 }
83};
84
85// this returns an instance of CopyOrMove, a prvalue
86// we are using copy elision
88{
89 // we created an instance here
90 // and return it to its called.
91 // Once the constructor called here
92 return { n };
93}
94
96{
97 // this assignment operator =() is never called.
98 // If we are using C++98 standard,
99 // then the constructor should have been called twice.
100 // then the constructor should have been called here too.
101 // and copy assignment operator=() should also have been called.
102
103 // But in modern C++, if we can use "Copy Elision"
104 // we do not create temporary to initialize our object.
106}
107
109{
110 // calls default constructor
111 CopyOrMove obj{n}; // obj is named
112
113 // CopyOrMove defines both copy constructor and move constructor
114 // When both are defined, then C++ prefers "Move Constructor" over Copy Constructor
115 // when passing prvalue, or pure rvalue as return value.
116
117 return obj; // we are returning named local object as prvalue.
118}
119
120// if we give optimization switch /O2 in case of MSVC,
121// Named Return Value Optimization kicks in.
122
123// Another point is that... giving optimization switch generates
124// totally different binary executable.
125//
126// If you ever watched my videos for a while, you probably have noticed that
127// I almost never use DEBUGGER...
128// The reason is ... generated code for debugging
129// is very different from release build.
131{
132 // initializing using move constructor of CopyOrMove
134}
135
136// it failed Named Return Value Optimization
137// because the return value of this function is different
138// object depending of if-branch
140{
141 CopyOrMove result { a }; // result is a named instance of CopyOrMove
142
143 if(a < b)
144 return result; // we return a named value
145 else
146 return CopyOrMove{ b }; // or we return an unnamed return value
147}
148
150{
152}
153
154// we should return the same instance of the return value or object
155// we are returning a named instance of CopyOrMove
156// taking advantage of Named Return Value Optimization technique
157// in this case, we have to Return The Same Named Instance
158// in all branches in the function().
160{
161 CopyOrMove result; // result is a named instance of CopyOrMove
162
163 if(a < b)
164 {
165 result.SetValue(a); return result;
166 }
167 else
168 {
169 result.SetValue(b); return result;
170 }
171}
172
174{
176}
177
178int main()
179{
180 // examples_for_copy_elision();
181
182 // example_for_named_return_value_optimization();
183
184 stream <<"Failed Named Return Value Optimization" << endl;
185
187
188 stream <<"\n\nSuccessful Named Return Value Optimization" << endl;
189
191}
CopyOrMove make_copy_or_move_Named_Return_Value_Optimization(int n)
tpf::sstream stream
void example_for_successful_named_return_value_optimization()
void examples_for_copy_elision()
CopyOrMove successful_named_return_value_optimization(int a, int b)
auto endl
CopyOrMove failed_named_return_value_optimization(int a, int b)
int main()
void example_for_named_return_value_optimization()
void example_for_failed_named_return_value_optimization()
CopyOrMove make_object_copy_elision(int n)
CopyOrMove(CopyOrMove &&right_hand_side)
CopyOrMove & operator=(CopyOrMove &&right_hand_side)
CopyOrMove & operator=(const CopyOrMove &right_hand_side)
void SetValue(int m)
CopyOrMove(int m=int{})
CopyOrMove(const CopyOrMove &right_hand_side)
constexpr auto endl
Definition: tpf_output.hpp:973
Stream output operators << are implemented.