7.06 std::out_of_range vs Compile-Time Bounded Ranges in Memory-Constrained Systems
Executive Summary: Analyzing std::logic_error and std::out_of_range exceptions in C++. We explore how out-of-bounds memory accesses corrupt adjacent variables or trigger MPU faults in bare-metal systems, and design zero-overhead compile-time bounded types.
💻 1. Annotated Source Code
#include <iostream> #include <vector> #include <stdexcept> using namespace std; int main() { vector<int> myNums; try { myNums.resize(myNums.max_size() + 1); } catch (const length_error& err) { cerr << "Caught a length_error: " << err.what() << endl; } cout << "Yay it's a big vector!" << endl; return 0; }
📐 2. Architecture & UML Class Model
<<class>>
std::logic_error
Standard Logic Exception
Attributes / Data Members
-_M_msg : std::string
Operations / Methods
+logic_error(msg: const string&)
+what() : const char*[override, noexcept]
<<class>>
std::length_error
Derived Logic Exception
Attributes / Data Members
(none / stateless)
Operations / Methods
+length_error(msg: const string&)
+what() : const char*[override, noexcept]
🔗 Architectural Relationships & Hierarchy
std::length_error
──▷
inherits
──▷
std::logic_error
📚 3. Core C++ Concepts Deep-Dive
1. Logic Errors vs Runtime Errors
std::logic_error indicates violations of logical preconditions that could theoretically be detected by examining the program source code (e.g. passing an index $\ge$ size to std::vector::at()).
2. Subclasses of std::logic_error
std::out_of_range: Accessing elements outside valid container boundaries.std::invalid_argument: Passing an improper argument to a function.std::length_error: Attempting to create an object exceedingmax_size.
⚡ 4. Embedded Systems & Hardware Reality
1. Out-of-Bounds Memory Corruption in Bare-Metal Systems
In standard C/C++, raw arrays (arr[i]) do not perform bounds checking. Writing past an array in embedded SRAM typically clobbers:
- Adjacent global or local variables.
- The function's Return Address on the stack, causing unpredictable jumps and HardFaults.
- Interrupt Vector Tables in SRAM (triggering catastrophic execution hijacking).
2. Bounded Index Types (Zero-Cost Safety)
Instead of throwing std::out_of_range at runtime, embedded engineers use clamped/saturating integer arithmetic or strongly-typed bounded index wrappers.
💡 5. Production-Ready Embedded Refactoring
Here is a compile-time bounded array index that prevents out-of-bounds bugs at compile time:
💡 Production-Ready Refactor
#include <cstdint> #include <cstddef> #include <array> template <typename T, size_t N> class SafeArray { std::array<T, N> data_{}; public: // 1. Clamped access: Guarantees no out-of-bounds without throwing constexpr const T& at_clamped(size_t index) const noexcept { if (index >= N) index = N - 1; return data_[index]; } // 2. Compile-time checked access for constant indices template <size_t Index> constexpr const T& get() const noexcept { static_assert(Index < N, "Array index is out of compile-time bounds!"); return data_[Index]; } };
📝 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 conceptual difference between std::logic_error and std::runtime_error?
Detailed Explanation:
std::logic_error reflects flaws in the program's internal reasoning (like violating function preconditions), whereas std::runtime_error reflects environment/hardware conditions outside the program's control.
Q2. What happens in C++ if you access an invalid index using the subscript operator (arr[index]) on a raw array?
Detailed Explanation:
Raw array subscripting (
[]) in C and C++ performs direct pointer arithmetic with zero bounds checking. Accessing invalid indices causes undefined behavior and potential memory corruption.
Q3. Which method on std::vector performs bounds checking and throws std::out_of_range on invalid access?
Detailed Explanation:
std::vector::at() checks whether the index is within the container bounds and throws std::out_of_range if it is not.
Q4. How does saturating/clamping arithmetic protect embedded sensor arrays from crashing?
Detailed Explanation:
Clamping ensures that invalid indices or arithmetic results saturate at the nearest valid boundary (e.g.
max_index), preventing out-of-bounds buffer corruptions.