C++ Library Extensions 2022.12.09
To help learn modern C++ programming
04-unique_ptr.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2
3/*
4 Please, please understand that std::unique_ptr should be your favorite tool
5 for any C++ programming.
6
7 It has only a single data membeer in std::unique_ptr<int>, that data member is
8 int*, the raw integer pointer.
9
10 You can convert std::unique_ptr to std::shared_ptr anytime.
11 About this, I will talk in future episode.
12
13 Keep this in mind that
14
15 auto - is copy semantic. It calls copy constructor/copy assigment
16 or, copy elision can ocur.
17
18 auto& - is lvalue reference. It can const int& or int&.
19 It can map to either const lvalue reference or just lvalue reference
20
21 auto&& - is rvalue reference. It can map to int&&. It cannot map to lvalue reference
22
23 But decltype(auto) can map to auto, auto&, auto&&.
24 So, decltype(auto) = one of auto, auto&, auto&&
25 */
26
29
30class DummyClass
31{
32 public:
33
34 using uptr_t = std::unique_ptr<int>;
35
36 public:
37 // I declared m_member in public section
39
40 DummyClass(int value=0):
41 m_member{ std::make_unique<int>(value) } { }
42
43 // returns as rvalue
44 // auto return_as_rvalue()
45 std::unique_ptr<int> return_as_rvalue()
46 {
47 return std::move(this->m_member);
48 }
49
50 // returns as rvalue reference
51 // this is correct!!!!
52 // auto&& return_as_rvalue_reference()
53 std::unique_ptr<int>&& return_as_rvalue_reference()
54 {
55 // this->m_member still exists
56 // after this function call.
57 // that is, the lifetime of this->m_member
58 // outlives this function block
59 return std::move(this->m_member);
60 }
61
63 // returns as rvalue
64 // std::unique_ptr<int> return_as_rvalue_with_auto()
66 {
67 return std::move(this->m_member);
68 }
69
70 // returns as rvalue reference
71 // this is correct!!!!
72 // std::unique_ptr<int>&& return_as_rvalue_reference_with_auto()
74 {
75 // this->m_member still exists
76 // after this function call.
77 // that is, the lifetime of this->m_member
78 // outlives this function block
79 return std::move(this->m_member);
80 }
81
82 // don't make such mistake!!!
83 // sadly, C++ compiler cannot catch such mistake
84 // this is wrong
85 std::unique_ptr<int>&& return_local_variable()
86 {
87 std::unique_ptr<int> local_ptr = std::make_unique<int>(20);
88
89 // the lifetime of local_ptr ceases
90 // when local_ptr goes off this block
91 return std::move(local_ptr);
92 }
93
94 // we should not return local unique_ptr
95 // neither as lvalue reference nor as rvalue reference
96 // this is the correct way to return local instance of unique_ptr
97 // in this case, the return type is concrete data type
98 std::unique_ptr<int> return_local_unique_ptr_properly()
99 {
100 auto local_ptr = std::make_unique<int>(10);
101
102 // this is correct!!
103 // return std::move(local_ptr); // std::move() is simply a typecast
104 // in case of this function, std::move() has no effect
105
106 return local_ptr;
107
108 /*
109
110 when std::move is used with return statement,
111 if the function's return type is decltype(auto),
112 then it matters... return std::move() does matter
113 if the return type of the function is declared with decltype(auto)
114 */
115 }
116};
117
118
120{
121 DummyClass dummy { 10 };
122
123 // we called return_as_rvalue_reference()
124 // and we have NOT caught the returned value
126
127 stream <<"Afer calling dummy.return_as_rvalue_reference()" << endl;
128
129 if(dummy.m_member)
130 {
131 stream <<"dummy.m_member is still valid" << endl;
132 }
133 else
134 {
135 stream <<"dummy.m_member is invalid" << endl;
136 }
137
138 // we called return_as_rvalue()
139 // and we have NOT caught the returned value
140 dummy.return_as_rvalue();
141
142 stream <<"Afer calling dummy.return_as_rvalue()" << endl;
143
144 if(dummy.m_member)
145 {
146 stream <<"dummy.m_member is still valid" << endl;
147 }
148 else
149 {
150 stream <<"dummy.m_member is invalid" << endl;
151 }
152}
153
155{
156 DummyClass dummy{10};
157
158 // catch the return value as rvalue reference
159 std::unique_ptr<int>&& p1 = dummy.return_as_rvalue_reference();
160
161 if(dummy.m_member)
162 {
163 stream << "dummy.m_member is still valid" << endl;
164 }
165 else
166 {
167 stream << "dummy.m_member is invalid" << endl;
168 }
169
170 // catch the return value as rvalue
171 std::unique_ptr<int> p2 = dummy.return_as_rvalue_reference();
172
173 if(dummy.m_member)
174 {
175 stream << "dummy.m_member is still valid" << endl;
176 }
177 else
178 {
179 stream << "dummy.m_member is invalid" << endl;
180 }
181}
182
184{
185 DummyClass dummy{10};
186
187 std::unique_ptr<int> p = dummy.return_local_variable();
188
189 stream <<"Am I okay?" << endl;
190}
191
193{
194 DummyClass dummy{10};
195
196 std::unique_ptr<int> p = dummy.return_local_unique_ptr_properly();
197
198 stream <<"Am I okay?" << endl;
199}
200
201int main()
202{
203 // understand_uncaught_return_value();
204
205 // test_function_returning_an_rvalue_reference();
206
207 // misfortune();
208
210
211 stream <<"Are you okay? " << endl;
212
213}
void the_correct_way()
tpf::sstream stream
void understand_uncaught_return_value()
auto endl
void misfortune()
void test_function_returning_an_rvalue_reference()
int main()
std::unique_ptr< int > return_local_unique_ptr_properly()
DummyClass(int value=0)
std::unique_ptr< int > && return_local_variable()
auto return_as_rvalue_with_auto()
std::unique_ptr< int > uptr_t
uptr_t m_member
std::unique_ptr< int > && return_as_rvalue_reference()
auto && return_as_rvalue_reference_with_auto()
std::unique_ptr< int > return_as_rvalue()
constexpr auto endl
Definition: tpf_output.hpp:973
Stream output operators << are implemented.