Project 5.10 Section 5 ⚡ Embedded Relevance: High Array References std::span Size Preservation Bounds Safety C++20

5.10 Passing Arrays by Reference (int(&)[N]) vs C++20 std::span in Embedded APIs

Executive Summary: Passing fixed arrays by reference (int(&)[N]) to prevent pointer decay. We analyze template-based array references and modern C++20 std::span for zero-overhead, non-owning contiguous memory views.

💻 1. Annotated Source Code

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

int productArray(array<int, 6> myArray);
void productArray(array<int, 6> myArray, int& result);

int main() {
	array<int, 6> numbers{ 1, 2, 3, 4, 5, 6 };

	int finalProduct;
	productArray(numbers, finalProduct);

	cout << "The product of the array elements (by reference) is: " << finalProduct << endl;

	/*int result = productArray(numbers);

	cout << "The product of the array elements is: " << result << endl;*/

	return 0;
}

int productArray(array<int, 6> myArray) {
	int product = 1;

	for (int num : myArray) {
		product *= num;
	}

	return product;
}

void productArray(array<int, 6> myArray, int& result) {
	result = 1;

	for (int num : myArray) {
		result *= num;
	}
}

📐 2. Architecture & UML Class Model

📐 Array Product Calculation via Reference Passing
+ Public - Private # Protected
<<compilation-unit>> ProductReferenceEngine Reference Pipeline
(none / stateless)
+computeArrayProduct(arr: const int*, size: size_t, productOut: int64_t&) : void

📚 3. Core C++ Concepts Deep-Dive

1. Passing Arrays by Reference Syntax

Writing void compute(int (&arr)[5]) passes the array by reference without decay. The compiler strictly enforces that only arrays of exactly length 5 can be passed.

2. C++20 std::span

std::span<T> is a lightweight non-owning view over any contiguous sequence of elements (pointer + size, 8 bytes total on 32-bit MCU).

⚡ 4. Embedded Systems & Hardware Reality

1. Unified Buffer Passing with std::span

In driver development, std::span<const uint8_t> can accept a C array, a std::array, or an RTOS buffer seamlessly with zero copying.

💡 5. Production-Ready Embedded Refactoring

Clean driver buffer API using std::span:

💡 Production-Ready Refactor
#include <cstdint>
#include <numeric>

// Non-decaying template array reference
template <typename T, size_t N>
T computeProduct(const T (&arr)[N]) noexcept {
    T product = 1;
    for (size_t i = 0; i < N; ++i) {
        product *= arr[i];
    }
    return product;
}

📝 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 key advantage of passing an array by reference using 'void func(int (&arr)[10])'?
A It prevents array-to-pointer decay, preserving compile-time size and preventing incorrect array sizes from being passed
B It makes the array dynamic
C It copies the array to the heap
D It doubles the array capacity
Detailed Explanation: Array references ((&arr)[N]) retain full array size metadata and cause compilation to fail if an array with different bounds is passed.
Q2. What is C++20 std::span?
A A lightweight, non-owning view over contiguous memory storing a pointer and element count (8 bytes on 32-bit MCU)
B A dynamic heap container that resizes automatically
C A thread synchronization primitive
D A hardware timer driver
Detailed Explanation: std::span represents a contiguous sequence of objects without owning the memory, encapsulating a pointer and length in a compact 8-byte structure.
Q3. Does passing a std::span<uint8_t> copy the underlying array buffer?
A No, std::span is a non-owning view; only the pointer and size are passed
B Yes, it creates a deep copy in SRAM
C Yes, it copies data to Flash
D It moves data to the heap
Detailed Explanation: std::span is a non-owning view; passing it passes only the pointer and length, performing zero buffer copying.
Q4. Can std::span prevent buffer overflows in embedded drivers?
A Yes, std::span tracks buffer size, allowing range-based iteration and bounds-checked .subspan() operations
B No, spans disable bounds checking
C Only on 64-bit systems
D Only if memory is allocated on the heap
Detailed Explanation: std::span retains element counts, enabling safe range-based iteration and bounded slicing.