Project 8.05 Section 8 ⚡ Embedded Relevance: High new[] delete[] Bounded Arrays etl::vector Heap Corruption

8.05 new[] / delete[] Pairing Rules vs Zero-Heap Fixed-Capacity Bounded Vectors

Executive Summary: Analyzing dynamic array allocation with new[] and deallocation with delete[]. We explain the undefined behavior of mismatched delete operators (scalar delete on array new), and demonstrate how embedded systems replace dynamic arrays with zero-heap fixed-capacity containers (such as ETL or inplace_vector).

💻 1. Annotated Source Code

#include <iostream>
using namespace std;

int main() {

	const int ARR_SIZE = 5;
	int arrSize = 0;

	cout << "Please enter an array size: ";
	cin >> arrSize;

	int* myArray = new int[arrSize];

	for (int i = 0; i < arrSize; i++) {
		myArray[i] = i * 2;
	}

	for (int i = 0; i < arrSize; i++) {
		cout << myArray[i] << endl;
	}

	delete[] myArray;
	myArray = nullptr;

	return 0;
}

📐 2. Architecture & UML Class Model

📐 Dynamic Array Scaling & Memory Leak Prevention
+ Public - Private # Protected
<<struct>> DynamicArrayTester Dynamic Array
+pArray : int32_t*
+arraySize : size_t
+allocate(n: size_t) : void
+fill(val: int32_t) : void
+free() : void[delete[] pArray]

📚 3. Core C++ Concepts Deep-Dive

1. Array Allocation (new[]) vs Scalar Allocation (new)

Allocating an array of $N$ objects requires new Type[N]. The runtime allocates memory for all elements plus internal array-size metadata (often stored in an invisible header prefix).

2. The Mismatched Deallocation Trap

Deallocating an array with scalar delete ptr; instead of delete[] ptr; is Undefined Behavior. In non-trivial classes, scalar delete calls the destructor of only the first element (ptr[0]) and corrupts the heap metadata manager.

⚡ 4. Embedded Systems & Hardware Reality

1. The Embedded Solution: Bounded Capacity Containers

Embedded applications need array-like containers with dynamic size (count of active elements) but bounded maximum capacity (zero heap allocation). Libraries like Embedded Template Library (ETL) provide etl::vector<T, Capacity>:

  • Storage is allocated directly inside the object (on the stack or in static RAM).
  • Element count can vary from $0$ to $Capacity$.
  • Zero dynamic memory allocations; zero heap fragmentation.

2. C++26 std::inplace_vector<T, N>

Standard C++26 standardizes this exact container as std::inplace_vector, bringing zero-heap vector semantics to modern C++ standard libraries.

💡 5. Production-Ready Embedded Refactoring

Here is an embedded fixed-capacity bounded array container with zero dynamic allocation:

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

template <typename T, size_t Capacity>
class BoundedVector {
private:
    std::array<T, Capacity> data_{};
    size_t size_{0};

public:
    constexpr bool push_back(const T& item) noexcept {
        if (size_ >= Capacity) return false; // Fixed capacity reached
        data_[size_++] = item;
        return true;
    }

    constexpr void clear() noexcept { size_ = 0; }
    constexpr size_t size() const noexcept { return size_; }
    constexpr size_t capacity() const noexcept { return Capacity; }

    constexpr T& operator[](size_t idx) noexcept { return data_[idx]; }
    constexpr const T& operator[](size_t idx) const noexcept { return data_[idx]; }
};

📝 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 happens if you allocate an array with 'new int[10]' and deallocate it with scalar 'delete myArray;' instead of 'delete[] myArray;'?
A Undefined Behavior occurs, potentially causing heap corruption and failing to call destructors for elements 1 through 9
B The compiler automatically fixes the syntax at runtime
C Only the last element is deleted
D The program executes 10% faster
Detailed Explanation: Calling scalar delete on an array allocated with new[] is undefined behavior. The runtime cannot determine the array length, destructors for subsequent elements are skipped, and heap bookkeeping is corrupted.
Q2. How does a Bounded Vector (like etl::vector or std::inplace_vector) differ from std::vector?
A Its elements are stored entirely within the container's inline storage on the stack/static memory without heap allocation
B It can grow infinitely in size
C It requires an operating system kernel
D It only accepts integer data types
Detailed Explanation: Bounded vectors allocate a fixed-capacity inline buffer inside the object itself, providing variable length up to a maximum capacity with zero dynamic heap allocation.
Q3. Why are Variable-Length Arrays (VLAs, e.g. int arr[n];) prohibited in safety-critical C++?
A They can silently blow past the available CPU stack size, causing catastrophic stack overflow crashes without any error handling
B They increase binary Flash size by 500KB
C They convert all variables to 64-bit doubles
D They disable compiler optimizations permanently
Detailed Explanation: VLAs allocate variable amounts of memory on the stack at runtime. If the size is large or uncontrolled, the stack silently collides with SRAM variables, causing catastrophic system crashes.
Q4. What is the time complexity of pushing an element to a BoundedVector with available capacity?
A O(1) strictly deterministic constant time
B O(N) linear time
C O(log N) logarithmic time
D O(N^2) quadratic time
Detailed Explanation: Because capacity is pre-allocated inline and never requires dynamic memory reallocation or element copying, inserting into a bounded vector is strictly $O(1)$ deterministic.