Lecture Notes 04 (CSI2372 - Advanced Programming Concepts With C++)

Download as pdf or txt
Download as pdf or txt
You are on page 1of 70

CSI2372 - Advanced Programming Concepts with C++

Instructor: Shahram Moradi


Contact: [email protected]
Office Hours: Tuesday 9:30 to 10:30 AM
Office: Room 344 ARC Building, 25 Templeton St., Ottawa, ON, Canada
Lecture hours: Mondays from 4 pm to 5:20 pm
Quizzes: Every Wednesdays from 2:30 pm to 3:50 pm - Online through Brightspace- Location is optional (home or classroom) – 1st attempt in this time
interval is mandatory and second attempt will have a deadline (lecture quizzes 10% + Lab quizzes 10% + tutorial quizzes 10% = overall 30%) – No lab
assignments
Final exam (40%): All modules covered in the course – Written exam
Midterm1 (15%): 16 October 2023 – Monday at 4 pm to 5:20 pm – Location is optional (home or classroom online) 1 attempt Online through Brightspace
Midterm2 (15%): 15 November 2023 – Wednesday at 2:30-3:50 pm – Location is optional (home or classroom) 1 attempt and Online through Brightspace
Teaching Assistant:
1. Bhattacharjee/Mayukh, email: [email protected]
2. Dai/Lansu, email: [email protected]
3. Emami Afshar/Bahar, email: [email protected]
4. Khare/Akshat, email: [email protected]
5. Kumar/Preyank, email: [email protected]
6. Yathirajulu/Ruchitha, email: [email protected]
7. Keswani /Yash, email: [email protected]

1
CSI2372 - Advanced Programming Concepts with C++
Course Outline:

Throughout this course, we will explore the following topics:


Module 1: Foundations of C++ Programming
• Session 1: Introduction and Contrasting C++ with Java Programming
• Session 2: C++ Data Types and Their Applications
• Session 3: Pointers, Memory Management, and Efficiency
❑ Midterm 1: Assessment covering Sessions 1-3
Module 2: Object-Oriented Paradigm and File Handling
• Session 4: Embracing Object-Oriented Programming in C++
• Session 5: Navigating File and Stream Input/Output in C++
• Session 6: Preprocessor Macros and Their Role
❑ Midterm 2: Assessment covering Sessions 4-6
Module 3: Templates, Computation, and Practical Applications
• Session 7: Harnessing Templates and the Standard Template Library
• Session 8: Numerical Computation Techniques using C++
• Session 9: Interface Integration with Hardware Components
• Session 10: Exploring Engineering Applications
❑ Final Exam: Comprehensive Assessment of All Modules

2
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency

• Low-Level Memory Access and Assembly


• Memory Allocators and Custom Allocators
• Garbage Collection Techniques
• Memory Profiling and Optimization
• Memory Safety in Different Languages
• Advanced Techniques in Virtual Memory

3
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency

Low-Level Memory Access and Assembly:


Exploring low-level memory operations with pointers.
Examining assembly language and memory manipulation.
Practical applications like memory-mapped I/O and kernel development.
Memory Allocators and Custom Allocators:
Designing and implementing custom memory allocators.
Memory pool management for improved performance.
Integrating custom allocators into data structures.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).
Implementing garbage collectors in languages like Java or C#.
Real-time and concurrent garbage collection.

4
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency

Memory Profiling and Optimization:


Using profiling tools to analyze memory usage.
Memory optimization techniques like object pooling.
Reducing memory fragmentation in long-running applications.
Memory Safety in Different Languages:
Memory safety in languages like C/C++ (e.g., RAII, smart pointers).
Memory management in managed languages (e.g., Java, C#).
Comparing Rust's ownership system with other languages.
Advanced Techniques in Virtual Memory:
Paging and segmentation in virtual memory systems.
Memory protection mechanisms and access control.
Memory-mapped files and their applications.

5
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.

Low-level memory access and assembly-level programming involve working closely with the physical memory of a
computer, typically at a level much closer to the hardware than most high-level programming languages.
Pointers play a crucial role in facilitating these low-level memory operations. To have a deep understanding of low-
level memory operations we need to know:

• Memory at the Hardware Level


• Pointers as Memory Addresses
• Memory Read and Write
• Assembly Language
• Memory Operations with Pointers

6
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.

Memory at the Hardware Level:


Computers store data in memory, which is typically organized as a linear sequence of bytes. Each byte has a
unique address. Low-level memory operations involve direct manipulation of memory addresses and their
contents.
Pointers as Memory Addresses:
Pointers in C++ store memory addresses. They point to a specific location in memory. In low-level programming,
pointers are used to access and manipulate data at precise memory locations.
Memory Read and Write:
With pointers, you can read data from a memory address or write data to it directly. This allows for efficient data
handling. Reading and writing memory directly can be faster than high-level operations but requires careful
management to avoid errors.

7
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.

Assembly Language:
Assembly language is a low-level programming language that uses prompts to represent machine-level
instructions. Programmers use assembly language to control the computer's hardware directly, including memory
access.
Memory Operations with Pointers:
Pointers in C++ can be used to interact with assembly language routines, enabling direct memory access. This can
be useful for tasks like working with hardware devices, optimizing performance-critical code, or interfacing with
operating system functions.

8
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.

#include <iostream>
int main() {
int value = 200;
int* ptr1 = &value; // Pointer pointing to the memory address of 'value'
int* ptr2 = &value; // Pointer pointing to the memory address of 'value'
// Reading from memory location using the pointer
//std::cout << "Value at memory address " << ptr << ": " << *ptr << std::endl;
// Initialize the pointer with nullptr (no memory address)
int* new_ptr = nullptr;
ptr1 = new_ptr;// Change the pointer to point to the new memory

9
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.

if (ptr1 == nullptr)
{std::cout << "First pointer is null" << std::endl;}
else {std::cout << "First pointer " << ptr1 << ":" << *ptr1 << std::endl;}
if (ptr2 == nullptr)
{std::cout << "Second pointer is null" << std::endl;}
else {std::cout << "Second pointer " << ptr2 << ": " << *ptr2 << std::endl;}
return 0;}

First pointer is null


Second pointer 0000005E1A10FB44: 200

10
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Exploring low-level memory operations with pointers.

In the previous slide, we used a pointer (nullptr) to exchange the values between two addresses which
is essential for read and write the value at a specific memory address. This demonstrates the basic
concept of low-level memory access with pointers.

Keep in mind that low-level memory operations should be used with CAUTION, as incorrect memory
manipulation can lead to crashes and instability. These techniques are typically reserved for specialized
tasks and optimization, and they require a deep understanding of hardware and memory
management.

11
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Examining assembly language and memory manipulation.

Examining assembly language and memory manipulation is important because it provides


insights into low-level instructions, registers, and memory management. This knowledge is
crucial for tasks like:
1. Kernel development involves building the core of an operating system, where precise
memory control is essential for system stability and resource management.
2. Memory-mapped I/O leverages memory manipulation to interact with hardware devices
directly, making it a fundamental aspect of system-level programming, embedded systems,
and device drivers.

12
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.

Notes before starting an example:

➢ #include <cstdint> //Platform-independent way to work with integers of specific sizes.


➢ volatile // Indicating that the value it points to may change unpredictably
➢ uint32_t* // A pointer to a 32-bit unsigned integer
➢ reinterpret_cast // Change the type of a variable or pointer, allowing reinterpretation of its binary
representation without altering its underlying bits.

➢ <volatile uint32_t*> // Enclose the type you are casting to


➢ (0x20000000) // 0x is a prefix that indicates hexadecimal number that equals to 536870912
➢ void moveLeft() // Initialize a void function
➢ {*MOVE_LEFT_REGISTER = 1;} // the value pointed to by MOVE_LEFT_REGISTER is set to 1.Memory MAP
I/O

13
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.

❑ Kernel development in C++ is highly specialized and typically involves writing code for embedded systems or
operating systems where you have direct control over hardware resources. Below is a simplified C++ example
illustrating the concept of controlling a robot arm using memory-mapped I/O in a hypothetical embedded
system:
#include <cstdint>// for fixed-size integer types: int8_t, int32_t, int64_t, uint32_t, uint64_t
// Define memory-mapped addresses for robot arm control
volatile uint32_t* CONTROL_REG = reinterpret_cast<volatile uint32_t*>(0x20000000); // Declare a pointer
'CONTROL_REG' as a volatile pointer to a 32-bit unsigned integer and initialize it to the memory address
'0x20000000' after performing a reinterpret_cast for low-level memory access.
volatile uint32_t* ARM_POSITION_REG = reinterpret_cast<volatile uint32_t*>(0x20000004); //Define constants for
arm movements
constexpr uint8_t ARM_MOVE_LEFT = 0x01; // 0x01 represents the decimal value 1.
constexpr uint8_t ARM_MOVE_RIGHT = 0x02; //0x01 represents the decimal value 2.
constexpr uint8_t ARM_STOP = 0x00; //0x01 represents the decimal value 0.
14
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.
#include <iostream>#include <cstdint> //Platform-independent way to work with integers of
specific sizes.
// Placeholder memory-mapped addresses for robot arm control registers
volatile uint32_t* ROBOT_BASE_ADDRESS = reinterpret_cast<volatile uint32_t*>(0x30000000);
//Declare a pointer 'ROBOT_BASE_ADDRESS' as a volatile pointer to a 32-bit unsigned integer,
and initialize it to the memory address '0x30000000' after performing a reinterpret_cast for
low-level memory access.
volatile uint32_t* MOVE_LEFT_REGISTER = ROBOT_BASE_ADDRESS + 0x04; //Declare a pointer
'MOVE_LEFT_REGISTER' as a volatile pointer to a 32-bit unsigned integer and set it to point to
the memory location at an offset of 4 bytes from 'ROBOT_BASE_ADDRESS' for low-level
memory access.
volatile uint32_t* MOVE_RIGHT_REGISTER = ROBOT_BASE_ADDRESS + 0x08;
// Example base 32 integer address//Volatile can change the variable anytime
15
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.

// Function to move the robot arm left or right using MMIO


void moveLeft() {*MOVE_LEFT_REGISTER = 1; } // Set the "move left" bit
void moveRight() {*MOVE_RIGHT_REGISTER = 1; } // Set the "move right" bit
//Define a function 'moveRight' that sets the value pointed to by 'MOVE_RIGHT_REGISTER' to 1,
which likely corresponds to triggering a rightward movement in a control system.

16
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.

int main() {
std::cout << "Robot arm is in the default position" << std::endl;
// Simulate moving the robot arm left and right using MMIO
moveLeft(); // or you can use moveRight();
std::cout << "Robot arm is moving left" << std::endl;
for (volatile int i = 0; i < 1000000; ++i) {// Add a delay with Iterate a volatile integer 'i' from 0 to 999,999
in a loop.
asm volatile("nop"); } //Execute an assembly language instruction "nop" (no operation) within
the loop, providing a brief pause or delay. //"no-operation" (nop)//asm is a keyword used to indicate
the start of inline assembly code.
std::cout << "Robot arm is moving right" << std::endl;

17
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Low-Level Memory Access and Assembly:
Practical applications like memory-mapped I/O and kernel development.

// Stop the robot arm (clear both "move left" and "move right" bits)
*MOVE_LEFT_REGISTER = 0;
*MOVE_RIGHT_REGISTER = 0; //Set the value pointed to by 'MOVE_RIGHT_REGISTER' to 0.
std::cout << "Robot arm is stopped" << std::endl;
return 0;}

18
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Designing and implementing custom memory allocators.

Designing/implementing a custom memory allocator in C++ involves managing memory allocation and
deallocation more efficiently or addressing specific application requirements.

#include <iostream> #include <cstdlib> // Include for malloc and free

class CustomAllocator {// Custom Memory Allocator Class

public:
CustomAllocator() {}
void* allocate(size_t size) {// Allocate memory of a specified size

void* ptr = std::malloc(size); // Allocate memory of the specified 'size' using 'std::malloc' and
store the pointer to the allocated memory in 'void* ptr'.
19
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Designing and implementing custom memory allocators.

if (!ptr) {throw std::bad_alloc(); } // If the pointer 'ptr' is null, it triggers an exception of type
'std::bad_alloc()' to handle memory allocation failure.
return ptr;}
// Handle Allocation Failure: The exclamation mark (!) is a logical NOT operator.//throw std::bad_alloc();
is used to explicitly throw an exception of the std::bad_alloc type, indicating a failure in memory
allocation. This exception can then be caught and handled by an appropriate exception handler further up
the call stack, allowing the program to respond to the memory allocation failure gracefully.

➢ "Further up the call stack" means that when an exception is thrown, the C++ runtime looks for an
exception handler in the sequence of function calls that led to the exception. It searches from the
current function back to the caller functions to find the first suitable handler to deal with the
exception. This allows for structured error handling and recovery even if the error occurred deep
within nested function calls.
20
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Designing and implementing custom memory allocators.

// Deallocate memory
void deallocate(void* ptr) {std::free(ptr);} ~CustomAllocator() {}}; //Define a 'deallocate' function that
takes a pointer 'ptr' and deallocates the memory using 'std::free,' and a destructor for 'CustomAllocator'
int main() {
CustomAllocator allocator; // Allocate memory using the custom allocator
int* intArray = static_cast<int*>(allocator.allocate(sizeof(int) * 5)); // Allocate memory for a readable
integer array of size 5 using a custom allocator, and indicate that the pointer represents an 'int*' array by
explicit casting.
// Use the allocated memory
for (int i = 0; i < 5; ++i) { intArray[i] = i * 10; }
// Deallocate the memory
allocator.deallocate(intArray);
return 0;}

21
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.

❑ Memory pool management is a technique used in software development to enhance performance and
reduce memory fragmentation. It involves pre-allocating a fixed-sized block of memory, known as a
MEMORY POOL, and then efficiently managing the allocation and deallocation of memory chunks from
within this pool. This approach can lead to several benefits:
• Reduced memory overhead
• Faster memory allocation
• Improved memory locality.

➢ Memory pool management is particularly useful in scenarios where memory allocation and deallocation
occur frequently, such as in real-time systems, embedded systems, or image processing applications. By
pre-allocating a pool of memory chunks and reusing them, you can minimize the overhead of dynamic
memory allocation and deallocation, which can be costly in terms of time and resources.

22
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.

#include <iostream>#include <vector>#include <cstring>


const int MEMORY_POOL_SIZE = 1024; // Define the size of the memory pool and chunk size
const int CHUNK_SIZE = 64;
class MemoryPool {public: // Custom memory pool class
MemoryPool() { // Initialize the memory pool
pool_.resize(MEMORY_POOL_SIZE);} // Allocate memory from the pool

void* allocate(size_t size) {if (size <= CHUNK_SIZE) {for (auto& chunk : pool_) {if (!chunk.allocated) {
chunk.allocated = true;
//Define a member function 'allocate' that takes a 'size_t' 'size' and, if 'size' is less than or equal to
'CHUNK_SIZE,' it searches through the 'pool_' for an unallocated 'MemoryChunk,' sets its 'allocated' flag to
'true,' and returns the 'data' pointer of that 'MemoryChunk'.
return chunk.data;}}}
return nullptr; // Allocation failed}
23
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.

void deallocate(void* ptr) { // Deallocate memory back to the pool


for (auto& chunk : pool_) { //Range-based for loop, which is used to iterate through elements in a
collection, such as an array, vector, or other iterable container.
//auto& chunk declares a reference variable chunk that will be used to represent each element in the collection
during each iteration.
if (chunk.data == ptr) {chunk.allocated = false;
break;}}} //If the 'data' member of a 'MemoryChunk' in the 'pool_' matches 'ptr,' set the 'allocated' member of
that 'MemoryChunk' to 'false' and exit the loop

private: struct MemoryChunk {bool allocated = false;//Define a private nested struct 'MemoryChunk' that
contains a boolean member 'allocated' initialized to 'false’

char data[CHUNK_SIZE];};
std::vector<MemoryChunk> pool_;};
24
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.
// Image processing function using memory pool
void processImage(MemoryPool& pool) {
➢ processImage is the name of the function. It's a user-defined function.
➢ MemoryPool is a custom class or library that provides memory allocation and management services.
➢ pool is a parameter of the MemoryPool& type. It represents an instance of the MemoryPool class or object that is passed
to the processImage function as an argument.
➢ The & in the function parameter MemoryPool& pool indicates that pool is passed by reference.
// Allocate memory from the pool
void* imageData = pool.allocate(64); // The 64 represents the size, in bytes, of the memory block that is being allocated.
// Simulate image processing (copy data)
if (imageData) {
std::memcpy(imageData, "Image Data", 11); // Copies the content of the string "Image Data" (including the null
terminator) into the memory location pointed to by imageData

25
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.

// Process the image data here


std::cout << "Image Processing: " << static_cast<char*>(imageData) << std::endl;
//Output the string 'Image Processing: ' followed by the content of the 'imageData' pointer, which is casted to a 'char*' to
interpret it as a C++-style string, and then followed by a newline.

➢ imageData is originally declared as a void* pointer, which means it doesn't specify the type of data it points to. By using
static_cast<char*>(imageData), you are telling the compiler to treat imageData as if it's pointing to a sequence of
characters (bytes).
➢ This cast allows you to work with the data pointed to by imageData as a sequence of characters, which is common when
dealing with binary data, raw memory, or byte-level manipulations.

pool.deallocate(imageData);} // Deallocate memory back to the pool


else {std::cout << "Memory allocation failed." << std::endl;}}
Why do we need to use char* for image processing? (Midterm Question)
26
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.

Why do we need to use char* for image processing? (Midterm Question)


1. Bytes: Images, just like any other digital data, are ultimately composed of individual bytes. These
bytes represent pixel values, color information, and other image details.
2. Memory Handling: When you work with binary data, it's important to have a way to represent and
manipulate individual bytes. A char* provides a convenient way to access and modify bytes in
memory.
3. Raw Data: Image data often includes binary information that is not necessarily text or characters.
Using a char* allows you to handle this raw binary data without interpreting it as text.
4. Flexibility: A char* can be used for a wide range of binary data types, not just images. It's a
versatile data type for working with raw memory.

27
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Memory pool management for improved performance.

int main() {
MemoryPool pool;
// Perform image processing with memory pool management
processImage(pool);
// Calling a function named processImage and passing a variable or object pool as an argument to the function.

❑ This is a common practice in programming to INVOKE a Function or Method with specific data or resources
for further processing or computation.

return 0;}

28
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

Integrating custom allocators into data structures in C++ involves designing data structures that
allow users to provide their own memory allocation strategies. This customization can be essential
for:
• Optimizing memory usage
• Improving performance
• Accommodating specific application requirements

❑ By integrating custom allocators, data structures can be more flexible and adaptable. Users can
choose how memory is allocated, which can be particularly valuable in scenarios where standard
memory allocation techniques are not suitable, such as real-time systems, embedded
environments, or when dealing with specialized hardware.

29
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

Let’s review an example to illustrates how to integrate custom allocators into a simple vector-like
data structure, providing users with the flexibility to manage memory allocation according to their
needs. In summary we will have:
• We define a CustomAllocator class that provides custom memory allocation and deallocation
methods.
• The CustomVector class is similar to the standard vector but allows users to specify a custom
allocator when creating an instance.
• The CustomVector class uses the custom allocator to allocate and deallocate memory for its
elements.
• In the main function, we will create a CustomVector of integers and populate it with values,
demonstrating how to use a custom allocator with the data structure.

30
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

T* allocate(size_t n) {return static_cast<T*>(std::malloc(n * sizeof(T)));}//Define a public member


function 'allocate' that allocates memory for 'n' objects of type 'T' using 'std::malloc' and returns a
pointer to the allocated memory, casted to type 'T*’
#include <iostream> #include <vector> #include <memory>
template <typename T>// Custom allocator class typename to indicate that T is a dependent type
class CustomAllocator {
public: void deallocate(T* p) {std::free(p);}}; //Define a public member function 'deallocate' that takes
a pointer 'p' of type 'T*' and deallocates the memory pointed to by 'p' using the 'std::free' function.

31
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.
// Custom vector-like data structure with integrated custom allocator
template <typename T, typename Allocator = CustomAllocator<T>>
//Define a template class with a primary template that takes a type 'T' and an optional template
parameter 'Allocator,' defaulting to 'CustomAllocator<T>.
class CustomVector {
public: CustomVector() : data(nullptr), size_(0), capacity_(0) {}
//Define a public constructor for the 'CustomVector' class that initializes the 'data' pointer to 'nullptr,'
'size_' to 0, and 'capacity_' to 0
explicit CustomVector(size_t initialCapacity, const Allocator& alloc = Allocator())
//Define an explicit constructor for the 'CustomVector' class that takes 'initialCapacity' as a size
parameter and an optional 'alloc' parameter of type 'Allocator' with a default value of 'Allocator()’.” An
explicit constructor is used to prevent implicit type conversions during object construction.

32
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

: data(alloc.allocate(initialCapacity)), size_(0), capacity_(initialCapacity) {}


//Initialize the 'data' member with memory allocated using the 'alloc' allocator, set 'size_' to 0, and
'capacity_' to 'initialCapacity'.
void push_back(const T& value) {
if (size_ >= capacity_) {reserve(capacity_ == 0 ? 1 : capacity_ * 2);} // Double the capacity if needed
//If the current size of the container is greater than or equal to its capacity, then call the 'reserve' function
to increase the capacity by either doubling the existing capacity or setting it to 1 if it's currently zero.

data[size_++] = value;} // Assign the 'value' to the 'data' array at the current 'size_' index and then
increment 'size_'

33
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

➢ 1: This is the value that is chosen if the condition (capacity_ == 0) is true. In this case, if the capacity is

currently zero, it sets the new capacity to 1.

➢ : This colon separates the true and false branches of the conditional.

➢ capacity_ * 2: This is the value that is chosen if the condition (capacity_ == 0) is false. If the capacity is

not zero, it doubles the current capacity (capacity_ * 2).

34
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

size_t size() const {return size_;}


//function returns the current number of elements (size) in the container as an unsigned integer
(size_t).

const T& operator[](size_t index) const {return data[index];}


//function allows read-only access (multiple const) to the element at the specified index in the
container and returns it as a constant reference to type T.

T& operator[](size_t index) {return data[index];}


//Function provides read-write access (there is no const) to the element at the specified index in the
container and returns it as a reference to type T. This allows you to modify the element's value at the
given index.
35
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

~CustomVector() {allocator.deallocate(data); } //Define the destructor '~CustomVector()' that


deallocates memory using the 'allocator'

➢ The ~CustomVector() function is a destructor that gets called when an instance of the
CustomVector class goes out of scope or is explicitly destroyed. In this case, it deallocates the
memory that was previously allocated for the vector's data using the custom allocator's deallocate
method.

This ensures that the memory is released when the vector is no longer needed, preventing memory
leaks.

36
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

private: T* data; //Declare a private member variable 'data' of type 'pointer to T', where 'T' can be any
data type.
size_t size_; //Declare a variable 'size_' of type 'size_t’ which is unsigned integer type
size_t capacity_; //Declare a variable 'capacity_' of type 'size_t'.
Allocator allocator; //Declare an instance of an 'Allocator' named 'allocator'
void reserve(size_t newCapacity) { //Define a function named 'reserve' that takes a size_t
parameter 'newCapacity'
T* newData = allocator.allocate(newCapacity);
//Allocate a new memory block of size 'newCapacity' using the 'allocator' and store the address in the
pointer 'newData'
for (size_t i = 0; i < size_; ++i) {newData[i] = data[i];}
37
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

❑ In the class's private section, vital components are defined for efficient data and memory management.
These include T* data for allocated data, size_t size_ to track element count, and size_t capacity_ for
capacity. The Allocator instance manages memory, and the void reserve(size_t newCapacity) function
efficiently allocates and copies data when needed, ensuring effective resource utilization.

38
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

T* newData = allocator.allocate(newCapacity); //Allocate a new memory block of size 'newCapacity'


using the 'allocator’ allocate and store the address in the pointer 'newData'
for (size_t i = 0; i < size_; ++i) {newData[i] = data[i];}//Copy data from the old memory block
('data') to the new memory block ('newData') element by element in a loop.
allocator.deallocate(data); //Free the memory previously allocated for 'data' using the 'allocator'
data = newData; //Update the 'data' pointer to point to the new memory block ('newData')
capacity_ = newCapacity;}};//Set the capacity of the container to the new value 'newCapacity'

39
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

We dynamically resize the previous allocated memories with the defined allocator and deallocator:
1. Allocates fresh memory with specified capacity.
2. Efficiently transfers existing data.
3. Deallocates old memory to prevent leaks.
4. Updates data pointer.
5. Adjusts capacity to new size, optimizing memory and performance.

40
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Allocators and Custom Allocators:
Integrating custom allocators into data structures.

int main() {
CustomVector<int> vec;
//Create an empty 'CustomVector' container of integers named 'vec’
for (int i = 1; i <= 10; ++i) {vec.push_back(i);}
//Add integers from 1 to 10 to the 'vec' container using 'push_back'
std::cout << "Vector size: " << vec.size() << std::endl; //vec.size() determines the size of the 'vec' container
for (size_t i = 0; i < vec.size(); ++i) {std::cout << vec[i] << " ";}
//Loop through the elements of 'vec' and print each element followed by a space.
std::cout << std::endl;
return 0;}

41
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).

In C++, memory management is primarily MANUAL, meaning the programmer is responsible


for allocating and deallocating memory. However, some libraries and tools can assist in
memory management. C++ does not have built-in garbage collection like some other
languages, but we can implement garbage collection manually or use third-party libraries if
needed. Two common garbage collection algorithms are "Mark-and-Sweep" and
"Generational Garbage Collection."

Mark-and-Sweep:
Mark-and-Sweep is a simple garbage collection algorithm that can be implemented in C++. It
works in two phases:
• Marking
• Sweeping
42
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).

❑ Marking Phase: In this phase, the algorithm IDENTIFIES all the memory objects that are
still in use by the program. It starts from root objects (e.g., global variables or objects on
the call stack) and recursively traverses the object graph, marking each visited object as
"alive.“

❑ Sweeping Phase: After marking, the algorithm scans the entire heap memory, freeing or
"sweeping" away any unmarked memory blocks. These unmarked blocks are considered
garbage because they are no longer accessible from the program.

43
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).

❑ Generational garbage collection is a memory management technique used in garbage


collection algorithms. It divides memory into multiple generations based on the age of
objects:
1. Young Generation
2. Old Generation
❑ Newly created objects are placed in a young generation, and objects that survive
multiple collections are promoted to older generations. This approach improves garbage
collection efficiency by focusing collection efforts on the younger generation, which
typically contains short-lived objects, while reducing the frequency of garbage collection
in older generations.

44
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).

Third party for garbage collection:


#include <iostream>
#include <gc/gc.h> // Include the Boehm GC header- This library should be installed
int main() {GC_INIT(); // Initialize the Boehm GC
// Allocate memory using the Boehm GC
int* myInt = (int*)GC_MALLOC(sizeof(int)); //Allocate memory for an integer using the 'GC_MALLOC'
function, and assign the pointer to the variable 'myInt' after casting it as an integer pointer.
if (myInt) {*myInt = 2023;
std::cout << "Value: " << *myInt << std::endl;}
else {std::cerr << "Memory allocation failed!" << std::endl;}
// The Boehm GC will automatically collect and free unused memory
return 0;}
45
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).

#include <iostream>
#include <vector>
// Define a simple object structure
struct MyObject {
int value;
bool marked;
MyObject* next;}; //Mark the 'next' object in the sequence recursively
//STEP 1: Function to mark objects as reachable
void mark(MyObject* obj);
{if (obj && !obj->marked) {obj->marked = true; //If 'obj' exists and is not marked, mark it as 'true'
mark(obj->next);}} //Mark the 'next' object in the sequence recursively

46
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).

// Function to sweep and deallocate unmarked objects


void sweep(std::vector<MyObject*>& objects) {
//Define a function 'sweep' that takes a vector of 'MyObject*' pointers from objects as its argument
for (auto it = objects.begin(); it != objects.end();) { //Iterate through the 'objects' collection from
the beginning to the end
MyObject* obj = *it;
if (obj->marked) {obj->marked = false; // If 'obj' is marked, unmark it.
++it} else {delete obj; // Deallocate unmarked object: If 'it' does not meet the condition, delete
'obj' and increment 'it'.
it = objects.erase(it)}}} // Remove 'it' from the 'objects' collection and move to the next
element

47
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).

int main() {std::vector<MyObject*> objects; // Create objects and simulate references

objects.push_back(new MyObject{1, false, nullptr});


objects.push_back(new MyObject{2, false, nullptr});
objects.push_back(new MyObject{3, false, nullptr}); //new MyObject{value = 1, isFlagSet = false,
pointer = nullptr}
objects[0]->next = objects[1]; // Simulate references
objects[1]->next = objects[2];
mark(objects[0]); // Mark objects as reachable
sweep(objects); // Sweep and deallocate unmarked objects
// Cleanup: manually delete remaining objects to avoid memory leaks
for (MyObject* obj : objects) {delete obj};
return 0;} 48
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency.
Garbage Collection Techniques:
In-depth study of garbage collection algorithms (e.g., mark-and-sweep, generational).

We define a MyObject structure that includes a marked flag to indicate whether an object is
reachable.
The mark function recursively marks objects as reachable starting from a root object.
The sweep function deallocates unmarked objects and removes them from the vector.
In the main function, we create objects, simulate references between them, mark them as
reachable, and then sweep and deallocate unmarked objects.

This is a basic illustration of a mark-and-sweep approach in C++. In practice, building a full-


featured garbage collector involves more complexity and considerations. For production use,
consider using established third-party libraries like the Boehm-Demers-Weiser garbage
collector mentioned earlier.

49
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Implementing garbage collectors in languages like Java or C#.

Strengths:
• Automatic memory management reduces memory-related errors.
• Enhanced safety improves program reliability.
• Easier development and maintenance due to reduced manual memory management.
• Efficient dynamic memory handling for complex lifetimes.
Weaknesses:
• Runtime overhead and non-deterministic pauses can impact performance.
• Resource consumption may be high.
• Limited control over memory management compared to C++.

50
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Implementing garbage collectors in languages like Java or C#.

Java
Automatic Garbage Collection: Java uses an automatic garbage collector that runs in the background and
manages memory for you. You don't need to explicitly allocate or deallocate memory.
Object Lifecycle: When you create objects in Java, they are allocated memory on the heap. The garbage
collector keeps track of which objects are still reachable from the program's root references (e.g., local
variables, object references).
Mark-and-Sweep: Java's garbage collector typically uses a generational garbage collection algorithm, which
includes a combination of techniques like mark-and-sweep and generational collection. Younger objects are
collected more frequently, while older ones are collected less often.
Tuning and Profiling: In Java, you can tune the garbage collector's behavior using command-line options or
configuration files. Profiling tools help you analyze and optimize garbage collection behavior for your specific
application.

51
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Implementing garbage collectors in languages like Java or C#.

C#

Garbage Collection in .NET: C# also provides automatic garbage collection through the Common Language
Runtime (CLR) in the .NET framework. Memory management is similar to Java, and you don't need to
manually allocate or deallocate memory.
Object Lifecycle: In C#, objects are allocated memory on the managed heap. The garbage collector tracks
object references and determines which objects are still in use.
Generational Garbage Collection: Like Java, C# uses generational garbage collection. It divides objects into
different generations based on their age. Newly created objects are placed in the youngest generation, and
they are collected more frequently. Older objects are promoted to older generations and are collected less
frequently.
Memory Profiling: .NET provides memory profiling tools like Visual Studio Profiler and third-party tools to
analyze and optimize memory usage and garbage collection behavior.
52
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Implementing garbage collectors in languages like Java or C#.

Practical Steps:
❑ In both Java and C#, you focus on writing your application code without worrying about manual
memory management.
❑ Use constructors to create objects, and the garbage collector takes care of reclaiming memory when
objects are no longer reachable.
❑ Be mindful of object references, especially when dealing with long-lived objects or event handlers, to
avoid unintentional memory leaks.
❑ Use profiling tools to identify memory-related issues, optimize memory usage, and fine-tune garbage
collection settings if necessary.
❑ In summary, practical implementation of garbage collection in Java and C# involves leveraging the
automatic garbage collection mechanisms provided by these languages and using profiling tools to
ensure efficient memory management and performance.

53
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Garbage Collection Techniques:
Real-time and concurrent garbage collection.

Garbage Collection (GC) can be realized in two broad approaches:

1. Real-Time GC: Ensures predictable and low-latency responses in critical applications. Collects
garbage incrementally, minimizing pause times, and allowing for real-time system performance.

2. Concurrent GC: Runs concurrently with the application, reducing pause times. Collects garbage
without stopping the program, making it suitable for interactive and server applications.

❑ Both techniques prioritize minimizing interruptions, critical for applications with severe
performance requirements.

54
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Profiling and Optimization:
Using profiling tools to analyze memory usage.

Profiling Tools: Utilize profiling tools to inspect memory usage, identify leaks, and discover performance
bottlenecks
• Heap Analysis: Analyze heap memory to pinpoint objects causing issues, enabling targeted
optimization.
• Resource Efficiency: Optimize memory usage for improved application performance and reduced
resource consumption.
• Critical for Scalability: Memory profiling is essential for ensuring applications scale efficiently as they
grow.

❑ Common profiling tools: Valgrind, gprof, Intel VTune Profiler, gperftools (Google Performance Tools), Perf,
Cachegrind, Heaptrack, Callgrind, gdb (GNU Debugger), AMD CodeXL

55
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Profiling and Optimization:
Memory optimization techniques like object pooling.

Object Pooling: A memory optimization technique that reuses pre-allocated objects, reducing
memory fragmentation and allocation overhead. Ideal for scenarios with frequent object
creation and destruction.

C++ DOES NOT have a built-in standard library for object pooling. Object pooling is typically
implemented as a custom solution or using third-party libraries.

Common object pooling libraries: Boost Pool, ObjectPool, Boost Object Pool, and
MemoryPoolCPP.

56
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Profiling and Optimization:
Memory optimization techniques like object pooling.

#include <iostream>
#include "ObjectPool.h" // Include the library header
int main() {// Create an object pool for integers
ObjectPool<int> intPool(10); // Pool size is 10
int* num1 = intPool.acquire(); // Acquire objects from the pool
int* num2 = intPool.acquire();
*num1 = 1001; // Use the acquired objects
*num2 = 1002;
intPool.release(num1); // Release objects back to the pool
intPool.release(num2);
return 0;}

57
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Profiling and Optimization:
Reducing memory fragmentation in long-running applications.

Fragmentation in Long-Running Applications: The phenomenon where memory becomes divided


into small, non-contiguous blocks over time, potentially leading to inefficient memory usage and
performance degradation.

Significance of memory optimization???

Reducing Fragmentation: Addressing memory fragmentation issues in long-running applications to


ensure:
1. Efficient memory utilization &&
2. Prevent performance degradation.

58
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory safety in languages like C/C++ (e.g., RAII, smart pointers).

❑ Achieving memory safety in languages like C/C++ through techniques such as Resource
Acquisition Is Initialization (RAII) and smart pointers.

❑ RAII: A C++ programming technique that ensures resources (like memory) are automatically
managed by tying their acquisition and release to the lifetime of an object. When an object is
created, it acquires the resource, and when it goes out of scope or is explicitly destroyed, it
releases the resource, thereby preventing resource leaks.

RAII functionality: Acquisition and Releasing of Resources

59
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory safety in languages like C/C++ (e.g., RAII, smart pointers).

❑ Creating RAII (Resource Acquisition Is Initialization) involves designing a C++ class in a way that resource
management is tied to the object's lifecycle. Here are the steps to create an RAII class:

1. Identify the Resource: Determine the resource you want to manage. It can be memory, a file, a network
connection, or any resource that requires explicit acquisition and release.
2. Create the Class: Define a C++ class specifically for managing this resource. This class will acquire the resource in
its constructor and release it in its destructor.
3. Constructor (Resource Acquisition): In the class constructor, write code to acquire the resource. For example, if
you're managing a file, you might open the file in the constructor.
4. Destructor (Resource Release): In the class destructor, write code to release the resource. For example, if you
opened a file in the constructor, you should close the file in the destructor.
5. Use the Class: Instantiate objects of this class wherever you need to work with the resource. RAII ensures that
the resource is automatically acquired when the object is created and released when the object goes out of
scope (e.g., at the end of a function or block).
60
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory safety in languages like C/C++ (e.g., RAII, smart pointers).
#include <iostream>
#include <fstream>
#include <stdexcept> //To throw an exception if there's an issue with opening the file for resource management.
class FileResource {public:
FileResource(const std::string& filename) : file(filename)
{if (!file.is_open()) {throw std::runtime_error("Failed to open file");}}
~FileResource() {if (file.is_open()) {file.close();}} // This is the destructor of the FileResource class. It is automatically
called when an object of the class goes out of scope or is explicitly destroyed.
private:// Add methods to operate on the file here
std::ofstream file;};
int main() {try {
FileResource resource("example.txt"); // RAII: FileResource automatically manages the file
resource.file << "Hello, RAII!" << std::endl; // Use the resource as needed (e.g., write to the file)
} // Resource is automatically released when 'resource' goes out of scope
catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;}
return 0;} 61
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory safety in languages like C/C++ (e.g., RAII, smart pointers).

➢ #include <fstream> //To work with file streams


➢ #include <stdexcept> //To throw an exception if there's an issue with opening the file for resource
management.

➢ ~FileResource() // This is the destructor of the FileResource class with the tilde sign. It is automatically called
when an object of the class goes out of scope or is explicitly destroyed.

➢ std::ofstream file;}; //It is used for writing data to files


➢ try {
// Begins a block of code where exceptions are monitored.
// Within the try block, if an exception is thrown, it can be caught and handled using catch blocks following the try
block.

62
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Memory management in managed languages (e.g., Java, C#).

In managed languages like Java and C#:

➢ Memory management is automatic and handled by the language runtime.

➢ Garbage collection is a core mechanism, where the runtime periodically identifies and reclaims

memory that is no longer in use, preventing common issues like memory leaks and dangling pointers.

➢ This approach simplifies memory management for developers BUT MAY INTRODUCE some runtime

overhead.

63
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Comparing Rust's ownership system with other languages.

Rust: A systems programming language that offers a unique approach to memory safety through its ownership
system.
❑ Unlike languages like C# and Java with garbage collection, Rust relies on compile-time checks to enforce
memory safety.
❑ This approach provides strong guarantees without runtime overhead, making Rust suitable for systems
programming and high-performance applications. Comparatively, languages like C and C++ rely more on
manual memory management, making them prone to memory-related bugs if not used carefully.
❑ Rust uses concepts like ownership, borrowing, and lifetimes to prevent common issues such as null pointer
dereferences and data races.
64
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Comparing Rust's ownership system with other languages.

Ownership: In Rust, ownership defines rules about which part of the code is responsible for managing a
resource's memory, ensuring its proper allocation and deallocation.(Memory Management Responsibilities)
Borrowing: Borrowing in Rust allows temporary access to a resource without transferring ownership,
ensuring that multiple parts of the code can use data safely.
Lifetime: Lifetimes in Rust specify the scope or duration for which references to data are valid, preventing the
use of references after the data is destroyed.
Buffer overflow: vulnerability where data overflows the allocated storage buffer's boundaries, potentially
overwriting adjacent memory, leading to unintended consequences: Crashes, Security Breaches, or Arbitrary
Code Execution.
65
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Memory Safety in Different Languages:
Comparing Rust's ownership system with other languages.

Runtime Overhead: Runtime overhead refers to the additional processing time and resources consumed by a
program due to runtime activities, such as garbage collection or dynamic memory allocation.
Data Race: A data race occurs in concurrent programming when two or more threads access shared data
simultaneously, potentially leading to unexpected and erroneous behavior.
Null Pointer Dereferencing: Null pointer dereferencing is the act of attempting to access or manipulate the
memory pointed to by a null (invalid) pointer, which can lead to crashes or undefined behavior.
Memory Bugs: Memory bugs are programming errors related to memory management, such as leaks
(unreleased memory), buffer overflows, or accessing uninitialized memory, which can result in program
instability or security vulnerabilities.
66
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Advanced Techniques in Virtual Memory:
Paging and segmentation in virtual memory systems.

Paging and segmentation are memory management techniques used in virtual memory systems.

Paging involves Dividing physical memory and virtual memory into Fixed-Size blocks (pages) and managing
them independently. It allows for efficient memory allocation but can lead to fragmentation.

Segmentation Divides memory into segments of Variable Sizes, each representing a logical unit. It offers
flexibility but may lead to fragmentation and complexity.

❑ In both cases we have fragmentation (losing actual memory) in the penalty of achieving efficient
memory management (Gaining efficient virtual memory access). So, these techniques enable efficient
memory allocation and protection in virtual memory systems, catering to diverse application needs and
system requirements.

67
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Advanced Techniques in Virtual Memory:.
Memory protection mechanisms and access control.

❑ Why virtual memory systems? It provides Memory Protection Mechanisms and ensures: data integrity
and system stability by controlling access to memory regions. These mechanisms enforce restrictions
on memory operations, preventing unauthorized modifications or access to protected memory areas,
enhancing security and stability in complex computing environments.

❑ How it works? As a C++ programmer, you don't need to call or manage virtual memory explicitly. The
operating system handles it behind the scenes. Your focus should be on proper memory management
practices within the C++ language, such as deallocating dynamically allocated memory to avoid
memory leaks and ensuring safe memory access to prevent issues like null pointer dereferences or
buffer overflows.

68
CSI2372 - Advanced Programming Concepts with C++
Module 1: Foundations of C++ Programming
• Session 3: Pointers, Memory Management, and Efficiency
Advanced Techniques in Virtual Memory:
Memory-mapped files and their applications.

Memory-mapped files allow files to be treated as regions of memory, facilitating efficient file I/O
operations by directly mapping file contents to virtual memory addresses. This technique enables
seamless integration of file data into a program's memory space, enhancing performance for tasks
like:

Process A
1. Large-scale data processing

Memory mapped file


2. Database systems
3. Inter-process communication
Process B

69
Thank you

70

You might also like