-
Notifications
You must be signed in to change notification settings - Fork 1
/
dyn_mem_alloc.hpp
617 lines (494 loc) · 25.4 KB
/
dyn_mem_alloc.hpp
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
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
#ifndef __DYNAMIC_MEMORY_ALLOCATION_H
#define __DYNAMIC_MEMORY_ALLOCATION_H
#include <iostream>
#include <iomanip>
#include <ios>
#include <array>
#include <new>
#include <ctime>
#include <cstdlib>
#include <cstdint>
#include <climits>
#include <bitset>
using namespace std;
/*
- Difference Between Stack and Heap:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Parameter | STACK | HEAP
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Basic Memory is allocated in a contiguous block. Memory is allocated in any random order.
- Allocation and De-allocation Automatic by compiler instructions. Manual by the programmer.
- Cost Less More
- Implementation Easy Hard
- Access time Faster Slower
- Main Issue Shortage of memory Memory fragmentation
- Locality of reference Excellent Adequate
- Safety Thread safe, data stored can only be accessed by the owner Not Thread safe, data stored visible to all threads
- Flexibility Fixed-size Resizing is possible
- Data type structure Linear Hierarchical
- Pr- eferred Static memory allocation is preferred in an array. Heap memory allocation is preferred in the linked list.
- Size Small than heap memory. Larger tha stack memory.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Difference Between Static and Dynamic Memory Allocation in C:
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Static Memory Allocation | Dynamic Memory Allocation
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- In the static memory allocation, variables get allocated permanently, | In the Dynamic memory allocation, variables get allocated only if your program unit gets active.
till the program executes or function call finishes.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Static Memory Allocation is done before program execution. | Dynamic Memory Allocation is done during program execution.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- It uses stack for managing the static allocation of memory. | It uses heap for managing the dynamic allocation of memory
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- It is less efficient | It is more efficient
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- In Static Memory Allocation, there is no memory re-usability | In Dynamic Memory Allocation, there is memory re-usability and memory can be freed when not required
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- In static memory allocation, once the memory is allocated, | In dynamic memory allocation, when memory is allocated the memory size can be changed.
the memory size can not change.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- In this memory allocation scheme, we cannot reuse the unused memory. | This allows reusing the memory. The user can allocate more memory when required.
Also, the user can release the memory when the user needs it.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- In this memory allocation scheme, execution is faster than dynamic memory allocation. | In this memory allocation scheme, execution is slower than static memory allocation.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- In this memory is allocated at compile time. | In this memory is allocated at run time.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- In this allocated memory remains from start to end of the program. | In this allocated memory can be released at any time during the program.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- This static memory allocation is generally used for array. | This dynamic memory allocation is generally used for linked list.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/
/*
- Allocating the dynamic memory by using 'new' keyword:
- Syntax:
- Allocating: ptr_name = new data_type;
- Ex:
int *ptr_name { nullptr };
ptr_name = new int; // Valid Memory Location: Allocating Space Dynamically On The Heap
*ptr_name = 789; // Valid Dereferencing: Writting to the allocated memory.
- Notes:
- Once you allcoated the pointer its belongs to the program.
- The system can NOT use this block of memory for anything else.
- Must defined by the same type of the pointer we pointing to.
- Releasing And Resetting the dynamic memory by using 'delete' && 'nullptr' keyword:
- Syntax:
- Releasing: delete ptr_name;
- Resetting: ptr_name = nullptr;
- Ex:
delete ptr_name; // Valid Releasing: Delete Memory Location
ptr_name = nullptr; // Valid Resetting: Reset to NULL
- Notes:
- On Releasing: Means returning that deleted location to the system.
- On Resetting: Means delete all data still remaining to secure that location for preventing memory leaks.
- Intializing at the same time declaring the pointer:
- Syntax:
- Junk Memory Location: int *ptr_name { new int }; // Valid
- Direct Initialization: int *ptr_name { new int (100) }; // Valid
- Uniform Intialization: int *ptr_name { new int {100} }; // Valid
- IMPORTANT Guidelines:
- Once you allocated the memory on the heap you can use anywhere.
- Remember To Use 'new' for Allocating a new memory location.
- Remember To Use the same data type you pointing to.
- Remember To Use 'delete' Release the memory location.
- Remember To Reset Using 'nullptr' to prevent data/memory Leaks.
- Remember After You Releasing And Resetting We Can Not Use That Location Again.
- Do NOT Initialize the pointer with 'nullptr'.
- Do NOT use 'delete' many times on the same pointer.
*/
void dyn_mem()
{
// Allocating
int *ptr_00 { nullptr }; // Junk Value
ptr_00 = new int;
*ptr_00 = 789; // Writting to it.
int *ptr_01 { new int };
*ptr_01 = 123;
int *ptr_02 { new int (100) };
int *ptr_03 { new int {100} };
std::cout
<< "ptr_00 Address: "
<< ptr_00
<< "\tptr_00 Value: "
<< *ptr_00
<< "\t\tptr_00 Size: "
<< sizeof ptr_00 << " bytes."
<< std::endl;
std::cout
<< "ptr_01 Address: "
<< ptr_01
<< "\tptr_01 Value: "
<< *ptr_00
<< "\t\tptr_01 Size: "
<< sizeof ptr_01 << " bytes."
<< std::endl;
std::cout
<< "ptr_02 Address: "
<< ptr_02
<< "\tptr_02 Value: "
<< *ptr_02
<< "\t\tptr_02 Size: "
<< sizeof ptr_02 << " bytes."
<< std::endl;
std::cout
<< "ptr_03 Address: "
<< ptr_03
<< "\tptr_03 Value: "
<< *ptr_03
<< "\t\tptr_03 Size: "
<< sizeof ptr_03 << " bytes."
<< std::endl;
std::cout << std::endl;
std::cout << std::endl;
// Releasing
std::cout << "Releasing: " << std::endl;
delete ptr_00;
delete ptr_01;
delete ptr_02;
delete ptr_03;
std::cout << "\tReleasing Done! " << std::endl;
// Resetting
std::cout << "Resetting: " << std::endl;
ptr_00 = nullptr;
ptr_01 = nullptr;
ptr_02 = nullptr;
ptr_03 = nullptr;
std::cout << "\tResetting Done! " << std::endl;
std::cout << std::endl;
std::cout << std::endl;
// Maybe system will crash [Because we deleted & resetted the memory locations]
// std::cout << ptr_00 << std::endl; // Invalid Data
// std::cout << ptr_01 << std::endl; // Invalid Data
// std::cout << ptr_02 << std::endl; // Invalid Data
// std::cout << ptr_03 << std::endl; // Invalid Data
// Outer scope
{
int *ptr_outer { new int {6009} };
// Inner scope
{
int *ptr_inner { new int {7007} };
std::cout
<< "ptr_inner Address: "
<< ptr_inner
<< "\tptr_inner Value: "
<< *ptr_inner
<< "\t\tptr_inner Size: "
<< sizeof ptr_inner << " bytes."
<< std::endl;
}
std::cout
<< "ptr_outer Address: "
<< ptr_outer
<< "\tptr_outer Value: "
<< *ptr_outer
<< "\t\tptr_outer Size: "
<< sizeof ptr_outer << " bytes."
<< std::endl;
// std::cout // error: ‘ptr_inner’ was not declared in this scope; did you mean ‘ptr_outer’?
// << "ptr_inner Address: "
// << ptr_inner
// << "\tptr_inner Value: "
// << *ptr_inner
// << "\t\tptr_inner Size: "
// << sizeof ptr_inner << " bytes."
// << std::endl;
}
// std::cout // error: ‘ptr_outer’ was not declared in this scope
// << "ptr_outer Address: "
// << ptr_03
// << "\tptr_outer Value: "
// << *ptr_outer
// << "\t\tptr_outer Size: "
// << sizeof ptr_outer << " bytes."
// << std::endl;
std::cout << std::endl;
std::cout << std::endl;
// Testing Valid Declarations & Definitions for Some Types:
int *test_ptr_int { new int { 1000 } };
float *test_ptr_float { new float { 4.5f } };
double *test_ptr_double { new double { 9.7 } };
char *test_ptr_char { new char { 'c' } };
bool *test_ptr_bool { new bool { false } };
long *test_ptr_long { new long { 7863487L }};
long long *test_ptr_long_long { new long long { 7863487L }};
short *test_ptr_short { new short { 128 } };
unsigned *test_ptr_unsigned { new unsigned { 55 } };
signed *test_ptr_signed { new signed { -55 } };
std::string *test_ptr_string { new std::string { "String" } };
// We Can NOT Using 'void'
// void *test_ptr_void { new void { void } };
// Releasing
delete test_ptr_int;
delete test_ptr_float;
delete test_ptr_double;
delete test_ptr_char;
delete test_ptr_bool;
delete test_ptr_long;
delete test_ptr_long_long;
delete test_ptr_short;
delete test_ptr_unsigned;
delete test_ptr_signed;
delete test_ptr_string;
// Resetting
test_ptr_int = nullptr;
test_ptr_float = nullptr;
test_ptr_double = nullptr;
test_ptr_char = nullptr;
test_ptr_bool = nullptr;
test_ptr_long = nullptr;
test_ptr_long_long = nullptr;
test_ptr_short = nullptr;
test_ptr_unsigned = nullptr;
test_ptr_signed = nullptr;
test_ptr_string = nullptr;
}
/*
- Dangling Pointers (Wild pointers ):
- Simple Definition:
- The pointers pointing to a deallocated memory block are known as Dangling Pointers.
- Occurs:
- when a pointer pointing to a variable goes out of scope or when an object/variable's memory gets deallocated.
- Side Effects:
- can result in some unexpected errors during the execution of a program, so we have to make sure to avoid them while writing a program.
- Types:
- Case 01): Uninitialized Pointer.
- Case 02): Deleted Pointer.
- Case 03): Multiple Pointer Pointing To The Same Memory Location.
- Solutions:
- Initialize your pointers.
- Reset the pointers after delete.
- For Multiple pointers to the same address, make sure the owner pointer is very clear.
- Golden Rule:
- With Each 'new' there is 'delete' & reset to 'nullptr'.
*/
void dangling_ptrs()
{
// ---------------------------------------------------------------------
// Case 01): Uninitialized Pointer.
// ---------------------------------------------------------------------
int *ptr_num_uninitialized; // Dangling Pointer.
std::cout << "Case 01): Uninitialized Pointer: " << std::endl;
std::cout
<< "\tptr_num_uninitialized Address: "
<< ptr_num_uninitialized // Pass
<< std::endl;
// Uncomment the next section will lead to crash the program!
// std::cout
// << "\tptr_num_uninitialized Value:"
// // Segmentation fault (core dumped)
// << *ptr_num_uninitialized // Fail & Crash!
// << std::endl;
// Releasing & Resetting
delete ptr_num_uninitialized;
ptr_num_uninitialized = nullptr;
// ---------------------------------------------------------------------
// Case 02): Deleted Pointer.
// ---------------------------------------------------------------------
std::cout << std::endl;
std::cout << "Case 02): Deleted Pointer: " << std::endl;
// Before Delete
int *ptr_num_ptr_should_deleted { new int { 789654123 } };
std::cout << "\tBefore Deleting: " << std::endl;
std::cout
<< "\t\tptr_num_ptr_should_deleted Address: "
<< ptr_num_ptr_should_deleted // Pass
<< std::endl;
std::cout
<< "\t\tptr_num_ptr_should_deleted Value: "
<< *ptr_num_ptr_should_deleted // Pass
<< std::endl;
// After Delete
delete ptr_num_ptr_should_deleted;
// ptr_num_ptr_should_deleted = nullptr; // Resetting Result: Segmentation fault (core dumped)
std::cout << "\tAfter Deleting: " << std::endl;
std::cout
<< "\t\tptr_num_ptr_should_deleted Address: "
<< ptr_num_ptr_should_deleted // Pass
<< std::endl;
std::cout
<< "\t\tptr_num_ptr_should_deleted Value: "
<< *ptr_num_ptr_should_deleted // Fail! Has Garbage Data
<< std::endl;
// ---------------------------------------------------------------------
// Case 03): Multiple Pointer Pointing To The Same Memory Location.
// ---------------------------------------------------------------------
std::cout << std::endl;
std::cout << "Case 03): Multiple Pointer Pointing To The Same Memory Location: " << std::endl;
int *ptr_multi_x { new int (123654789) }; // Named: Owner Pointer
// This pointer pointing to the same location of 'ptr_multi_x'
int *ptr_multi_y { ptr_multi_x }; // Named: Slave Pointer.
std::cout << "\tBefore Deleting: " << std::endl;
// Printing out ptr_multi_x, ptr_multi_y:
std::cout
<< "\t\tptr_multi_x Address: "
<< ptr_multi_x // Pass
<< "\t\tptr_multi_x Value: "
<< *ptr_multi_x // Pass
<< std::endl;
std::cout
<< "\t\tptr_multi_y Address: "
<< ptr_multi_y // Pass
<< "\t\tptr_multi_y Value: "
<< *ptr_multi_y // Pass
<< std::endl;
std::cout << "\tAfter Deleting: " << std::endl;
// Deleting 'ptr_multi_x':
// Maybe leads to undefined behaviour: Garbage Value!, or Crashs!
delete ptr_multi_x;
// Printing out ptr_multi_x, ptr_multi_y:
std::cout
<< "\t\tptr_multi_x Address: "
<< ptr_multi_x // FAIL!
<< "\t\tptr_multi_x Value: "
<< *ptr_multi_x // FAIL!
<< std::endl;
std::cout
<< "\t\tptr_multi_y Address: "
<< ptr_multi_y // FAIL!
<< "\t\tptr_multi_y Value: "
<< *ptr_multi_y // FAIL!
<< std::endl;
std::cout << std::endl;
std::cout << std::endl;
}
/*
- Handling a memory allocation failure:
- When?:
- You do memory allocation using new in C++ and it fails.
- Explaination:
- Answer:
When we allocate memory from heap dynamically in a C++ program using new operator,
the program crashes when memory is not available,
or the system is not able to allocate memory to a program,
as it throws an exception. So, to prevent program crash,
we need to handle the exception when memory allocation fails.
- Solutions:
- 01) Using Try Catch Block with 'std::bad_alloc' exception.
- 02) Using 'std::nothrow' setting version of “new” i.e. new(std::nothrow).
*/
void dyn_mem_alloc_fails()
{
// error: size ‘15503280078736850944’ of array exceeds maximum object size ‘9223372036854775807’
// int *ptr_huge_array_size { new int [9223372036854775807] }; // Fail!
// 01) Solution Using C++ Exception:
try
{
int *ptr_huge_array_size_sol_01 { new int [INT_MAX] };
if(ptr_huge_array_size_sol_01 == nullptr)
std::cout << "Memory Allocation Failed!" << std::endl;
else
std::cout << "Memory Allocation Succeeded!" << std::endl;
// Releasing & resetting
delete ptr_huge_array_size_sol_01;
ptr_huge_array_size_sol_01 = nullptr;
}
catch(std::exception& ex)
{
// printint out the exception message:
std::cout
<< "Oh Yeah!, We have an exception: "
<< "\t"
<< ex.what()
<< std::endl;
}
// 02) Solution Using 'std::nothrow':
int *ptr_huge_array_size_sol_02 { new(std::nothrow) int [INT_MAX] };
if(ptr_huge_array_size_sol_02 == nullptr)
std::cout << "Memory Allocation Failed!" << std::endl;
else
std::cout << "Memory Allocation Succeeded!" << std::endl;
std::cout << std::endl;
std::cout << std::endl;
// Releasing & Resetting
delete ptr_huge_array_size_sol_02;
ptr_huge_array_size_sol_02 = nullptr;
}
/*
- Null Pointer Safety:
- Guidelines:
- Do Not 'delete' any pointer before check it is null or not.
- Double Check 'nullptr' before any operations.
*/
void nullptr_safety()
{
char *ptr_ch {};
delete ptr_ch; // Must Check before Deletion
if(ptr_ch) // if(ptr_ch != nullptr)
std::cout << "Pointer ptr_ch has a valid address." << std::endl;
else
std::cout << "Pointer ptr_ch has not a valid address." << std::endl;
}
/*
- Memory Leaks
- What?:
- when programmers allocates memory by using new keyword and forgets to deallocate the memory by using delete() function or delete[] operator.
- Requires:
- We Must Release & Reset The Pointer Before Using Again.
- Instead of managing memory manually, try to use smart pointers where applicable.
- Never use a raw pointer unless it’s to interface with an older lib.
- Allocate memory by new keyword and deallocate memory by delete keyword and write all code between them.
- use std::string instead of char *. The std::string class handles all memory management internally, and it’s fast and well-optimized.
*/
void mem_leaks()
{
int *ptr_leak (new int(15));
std::cout
<< "ptr_leak Address:\t"
<< ptr_leak
<< "\tptr_leak Value:\t"
<< *ptr_leak
<< std::endl;
std::cout << std::endl;
std::cout << std::endl;
// We Must Release & Reset The Pointer Before Using Again
// delete ptr_leak;
// ptr_leak = nullptr;
ptr_leak = new int(51); // Danger!!!: Memory Will Leaks Here
std::cout
<< "ptr_leak Address:\t"
<< ptr_leak
<< "\tptr_leak Value:\t"
<< *ptr_leak
<< std::endl;
std::cout << std::endl;
std::cout << std::endl;
}
/*
- Dynamic Arrays:
- Living on the Heap.
- Allocated with 'new' keyword and can using 'std::nothrow'
- Syntax:
- Allcoating:
- type_name *ptr_name { new type_name[SIZE] };
- type_name *ptr_name { new(std::nothrow) type_name[SIZE] };
- type_name *ptr_name { new type_name[SIZE] {1, 2, 3, 4, 5} };
- type_name *ptr_name { new(std::nothrow) type_name[SIZE] {1, 2, 3, 4, 5}};
- Releasing:
- delet[] ptr_name;
- Resetting
- ptr_name = nullptr;
*/
void dyn_arr_alloc()
{
size_t size { 10 };
// 01) Allocate a new array dynamically with no value
double *ptr_arr_of_salaries { new double[size] }; // Initializing with garabage values
// 02) Allocate a new array dynamically with default value using 'std::nothrow' setting
int *ptr_arr_of_levels { new(std::nothrow) int[size] {} }; // Initializing with 0
// 03) Allocate a new array dynamically with some values using 'std::nothrow' setting
float *ptr_arr_of_shades { new(std::nothrow) float[size] { 0.9f, 5.9f, 6.7f} }; // Initializing on 3 values the remaining will be 0.0f
if(ptr_arr_of_shades) // Check Null Safety Before Do Any Operations
for(int i = 0; i < size; ++i)
std::cout << i << ")\t"<< ptr_arr_of_shades[i] << std::endl;
else
std::cout << "Sorry! Invalid Allocation of An Array." << std::endl;
// Releasing
delete[] ptr_arr_of_salaries;
delete[] ptr_arr_of_levels;
delete[] ptr_arr_of_shades;
// Resetting
ptr_arr_of_salaries = nullptr;
ptr_arr_of_levels = nullptr;
ptr_arr_of_shades = nullptr;
}
#endif