-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathUniquePtr.cpp
More file actions
292 lines (235 loc) · 8.09 KB
/
UniquePtr.cpp
File metadata and controls
292 lines (235 loc) · 8.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
// ===============================================================================
// UniquePtr.cpp // std::unique_ptr
// ===============================================================================
module;
#include <stdio.h>
#include <windows.h>
module modern_cpp:unique_ptr;
namespace UniquePointerGeneral {
static void test_01()
{
// create a unique_ptr to an int with value 123
std::unique_ptr<int> ptr1{ new int{ 123 } };
// or
// std::unique_ptr<int> ptr1{ std::make_unique<int>(123) };
// or
// auto ptr1{ std::make_unique<int>(123) };
// access value behind smart pointer
int n{ *ptr1 };
std::println("*ptr1: {}", n);
// access value using raw pointer
int* ip{ ptr1.get() };
(*ip)++;
int m{ *ip };
std::println("*ip: {}", m);
// access value - again - behind smart pointer
m = *ptr1;
std::println("*ptr1: {}", m);
// move construction:
// second std::unique_ptr by moving 'ptr1' to 'ptr2',
// 'ptr1' doesn't own the object anymore
std::unique_ptr<int> ptr2{ std::move(ptr1) };
// std::println("*ptr1: {}", *ptr1); // crashes
m = *ptr2;
std::println("*ptr2: {}", m);
{
// move assignment
std::unique_ptr<int> ptr3{};
ptr3 = std::move(ptr2);
m = *ptr3;
std::println("*ptr3: {}", m);
}
// Note: pointer behind std::unique_ptr's has been released
}
// ===========================================================================
static std::unique_ptr<int> loadUniquePointer()
{
std::unique_ptr<int> ptr{ std::make_unique<int>(100) };
return ptr;
}
static void storeUniquePointer(std::unique_ptr<int>& ptr)
{
std::println("*ptr: {}", *ptr);
(*ptr)++;
std::println("*ptr: {}", *ptr);
// take ownership right now:
// std::unique_ptr<int> ptr2{ std::move(ptr) };
}
static void storeUniquePointerSafe(const std::unique_ptr<int>& ptr)
{
std::println("*ptr: {}", *ptr);
(*ptr)++;
std::println("*ptr: {}", *ptr);
// ownership CANNOT be taken right now - ptr is const:
// std::unique_ptr<int> ptr2{ std::move(ptr) };
}
static void storeUniquePointerAlternate(int* ptr)
{
std::println("*ptr: {}", *ptr);
(*ptr)++;
std::println("*ptr: {}", *ptr);
// A) taking ownership right now: MAKES NO SENSE
// B) delete: Under no circumstances:
// pointer is owned by accompanied Unique Ptr
}
static void test_02()
{
// retrieving a unique pointer from a function
std::unique_ptr<int> ptr{ loadUniquePointer() };
std::println("*ptr: {}", *ptr);
// provide a function with a unique pointer: who owns the pointer now?
storeUniquePointer(ptr);
// C++ Core Guidelines
storeUniquePointerAlternate(ptr.get());
// does this work?
std::println("*ptr: {}", *ptr);
}
// ===========================================================================
// std::unique_ptr with arrays
class A {
public:
A() {
std::println("Constructor A called");
}
~A() {
std::println("Destructor A called");
}
};
static void test_03()
{
// creates a unique_ptr to an array of 5 A objects
std::unique_ptr<A[]> ptr{ std::make_unique<A[]>(5) };
ptr.reset();
}
// ===========================================================================
}
namespace UniquePointer_SourceSinkPattern
{
static std::unique_ptr<int> createResource(int value)
{
std::unique_ptr<int> ptr{ std::make_unique<int>(value) };
return ptr;
}
static void consumeResource(std::unique_ptr<int> ptr) // call by-value (!)
{
std::println("*ptr: {}", *ptr);
// now *ptr is deleted
}
static void test_04()
{
// creating a unique pointer with the help of a creator function
std::unique_ptr<int> ptr{ createResource(123) };
std::println("*ptr: {}", *ptr);
// Pass unique pointer to another function:
// No need for explicit std::move, temporary is captured as R-Value reference
// so the std::unique_ptr's move constructor is automatically invoked
consumeResource(createResource(456));
}
}
namespace UniquePointerWrappingResourceHandles {
// stateless callable object to close FILE files
struct FILE_Deleter
{
void operator() (FILE* pFile) const
{
if (pFile != (FILE*)0) {
fclose(pFile);
}
}
};
using FILE_UniquePtr = std::unique_ptr<FILE, FILE_Deleter>;
static FILE_UniquePtr make_fopen(const char* fileName, const char* mode)
{
FILE* file{ nullptr };
auto err{ fopen_s(&file, fileName, mode) };
if (err != 0)
{
// print error info
std::println("Cannot open file {}!", fileName);
return nullptr;
}
return FILE_UniquePtr{ file };
}
static void test_05()
{
const char* fileName{ "..\\GeneralSnippets\\UniquePtr\\UniquePtr.cpp" };
FILE_UniquePtr pInputFilePtr{ make_fopen(fileName, "r") };
if (!pInputFilePtr) {
std::println("Done.");
return;
}
else {
FILE* fp{ pInputFilePtr.get() };
char buf[512];
fgets(buf, sizeof(buf), fp);
std::print("First Line: {}", buf);
}
}
}
namespace UniquePointerWrappingWin32Handles {
// stateless callable object to release Win32 handles
struct HANDLE_Deleter
{
void operator() (HANDLE handle) const
{
if (handle != INVALID_HANDLE_VALUE) {
::CloseHandle(handle);
}
}
};
using HANDLE_UniquePtr = std::unique_ptr<void, HANDLE_Deleter>;
static HANDLE_UniquePtr make_Win32_HANDLE(HANDLE handle)
{
if (handle == INVALID_HANDLE_VALUE or handle == nullptr) {
return HANDLE_UniquePtr{ nullptr };
}
return HANDLE_UniquePtr{ handle };
}
static void test_06()
{
const auto* fileName{ L"..\\GeneralSnippets\\UniquePtr\\UniquePtr.cpp" };
HANDLE hFile = ::CreateFile (
fileName, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // normal file
NULL
);
HANDLE_UniquePtr uniquePtr { make_Win32_HANDLE(hFile ) };
if (! uniquePtr) {
return;
}
else {
char buffer[512] = { 0 };
OVERLAPPED ol = { 0 };
if (::ReadFileEx(hFile, buffer, sizeof(buffer) - 1, &ol, NULL) == 0) {
std::println("Done.");
return;
}
else
{
std::println("First part of File:");
std::println("{}", buffer);
}
}
}
}
// =====================================================================================
void main_unique_ptr()
{
using namespace UniquePointerGeneral;
test_01();
test_02(); // interaction with functions/methods
test_03(); // support of arrays
using namespace UniquePointer_SourceSinkPattern;
test_04();
using namespace UniquePointerWrappingResourceHandles;
test_05();
using namespace UniquePointerWrappingWin32Handles;
test_06();
}
// =================================================================================
// End-of-File
// =================================================================================