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
<<class>>
Buffer
Rule of Five Buffer
Attributes / Data Members
-data : int32_t*
-size : size_t
Operations / Methods
+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?
Detailed Explanation:
Static bounded buffers allocate fixed storage at compile time, eliminating all runtime heap allocation, memory leaks, and fragmentation.