Project 11.07 Section 11 ⚡ Embedded Relevance: High Buffer Management Deep Copy Rule of Three Dynamic Memory Memory Leaks

11.07 Deep Copy, Destructor Safety, and Bounded Buffer Alternatives

Executive Summary: Hands-on implementation of a custom dynamic buffer class adhering to the Rule of Three. We inspect deep copy allocation, memory leak prevention, and bounded static buffer alternatives for microcontrollers.

💻 1. Annotated Source Code

#ifndef BUFFER_H
#define BUFFER_H

#include <iostream>
#include <cstring>
using namespace std;

class Buffer {
	public:
		Buffer(const char* input) {
			cout << "Constructor called" << endl;
			length = strlen(input);
			data = new char[length + 1];
			strcpy_s(data, strlen(input) + 1, input);
		}//end ctor

		~Buffer() {
			cout << "Destructor called!" << endl;
			delete[] data;
		}//end dtor

		//copy ctor
		Buffer(const Buffer& other) {
			cout << "Copy constructor called" << endl;
			length = other.length;
			data = new char[length + 1];
			strcpy_s(data, strlen(other.data) + 1, other.data);
		}

		//copy assignment
		Buffer& operator=(const Buffer& other) {
			cout << "Copy assignment called" << endl; 
			if (this != &other) {
				delete[] data;
				length = other.length;
				data = new char[length + 1];
				strcpy_s(data, strlen(other.data) + 1, other.data);
			}

			return *this;
		}

		//move constructor
		Buffer(Buffer&& other) noexcept {
			cout << "Move constructor called" << endl;
			data = other.data;
			length = other.length;
			other.data = nullptr;
			other.length = 0;
		}

		//move assignment
		Buffer& operator=(Buffer&& other) noexcept {
			cout << "Move assignment called" << endl;
			if (this != &other) {
				delete[] data;
				data = other.data;
				length = other.length;
				other.data = nullptr;
				other.length = 0;
			}

			return *this;
		}

		//print
		void print() const{
			cout << "Buffer contents: " << (data ? data : "null") << endl;
		}

	private:
		char* data;
		size_t length;
};

#endif 
#include "Buffer.h"
#include <iostream>
using namespace std;

int main() {

	cout << "\nCreating Buffer a...." << endl;
	Buffer a("Hello");

	cout << "\nCopying a to b ..." << endl;
	Buffer b = a;

	cout << "\nMoving a to c..." << endl;
	Buffer c = move(a);

	cout << "\nAssigning b to d..." << endl;
	Buffer d("Temp");
	d = b;

	cout << "\nMoving c to e..." << endl;
	Buffer e("Temp");
	e = move(c);

	cout << "\nPrinting all buffers..." << endl;

	b.print();
	d.print();
	e.print();

	cout << "\nEnd of main" << endl;

	return 0;
}

📐 2. Architecture & UML Class Model

📐 Rule of Five Dynamic Buffer Challenge Architecture
+ Public - Private # Protected
<<class>> Buffer Rule of Five Buffer
-data : int32_t*
-size : size_t
+Buffer(size: size_t)
+~Buffer()[delete[] data]
+Buffer(const Buffer&)[Copy Ctor]
+operator=(const Buffer&) : Buffer&[Copy Assign]
+Buffer(Buffer&&) : noexcept[Move Ctor]
+operator=(Buffer&&) : Buffer&[Move Assign]

📚 3. Core C++ Concepts Deep-Dive

1. Deep Copy Implementation

When copying a buffer, memory must be allocated independently for the destination instance, followed by copying the data payload using std::copy or memcpy.

⚡ 4. Embedded Systems & Hardware Reality

1. Bounded Static Buffers vs Dynamic Buffers

In safety-critical firmware, dynamic buffers should be replaced with fixed-capacity stack/static buffers (std::span or std::array) to guarantee zero heap fragmentation and deterministic lifetime.

💡 5. Production-Ready Embedded Refactoring

💡 Production-Ready Refactor
#include <array>
#include <cstdint>
#include <iostream>

template <size_t BoundedCapacity>
class StaticBuffer {
public:
    bool append(uint8_t byte) {
        if (size_ >= BoundedCapacity) return false;
        data_[size_++] = byte;
        return true;
    }
    size_t size() const { return size_; }
private:
    std::array<uint8_t, BoundedCapacity> data_;
    size_t size_ = 0;
};

📝 Knowledge Verification Quiz

Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.

Q1. What is the primary benefit of replacing dynamic buffers with bounded static buffers in embedded firmware?
A Guaranteed memory allocation at compile-time with zero heap fragmentation.
B Ability to resize buffers infinitely.
C Automatic networking support.
D Slower CPU frequency.
Detailed Explanation: Static bounded buffers allocate fixed storage at compile time, eliminating all runtime heap allocation, memory leaks, and fragmentation.