Using an array of function pointers in a class

Sorry, i meant OP

No hidden magic, just templates for vectors, maps, lists, ... I can't understand why they are not supported on AVR boards. There is no reason they would use more memory than it is necessary.

I think the question is: who is prepared to maintain the entire C++ standard library for an obsolete 8-bit microcontroller?

Even AVR-libc only has a handful of frequent contributors, there were talks about dropping AVR support from GCC a couple of years back, and Microchip themselves are at least 7 versions of GCC behind for their latest toolchain ...

1 Like

In the STL, memory allocation failures use try-catch to throw exceptions like std::bad_alloc, which increases memory usage due to the additional stack space and larger binary size required for exception handling.

This dynamic memory management also risks fragmentation in systems with limited resources, like AVR microcontrollers.

There is also dependency on iterators which themselves are lightweight and don’t significantly contribute to code size, but their use with dynamic containers can increase binary size, especially when exception handling is enabled.

Disabling exceptions reduces memory overhead but removes automatic error handling for allocation failures. We see from time to time how the String class wreaks havoc either because calls silently fails when not crashing the arduino or due to fragmented heap.

My guess is that the Arduino team assessed the risk/value of having better C++ features versus code failure for beginners and artists who would have no clue about what’s happening under the hood.


Side note : GCC implements try-catch by generating code that sets up a catch table when entering a try block, which contains information about catch handlers. If an exception is thrown, the stack unwinding process deallocates resources and calls destructors for stack objects while searching the catch table for a matching handler. This mechanism increases memory usage due to the additional metadata required for exception handling and the overhead associated with stack manipulation.

2 Likes

I'm not clear if you are saying that any use of the STL risks problems with memory management or exception handling or if only some features (is that the correct term) carry that risk.

Does the code presented by @gfvalvo carry that risk?

I suspect that the way stack or heap fragmentation is usually presented on the forum is wrong, but I don't have enough knowledge to back up my suspicion. However, this is my topic so...
Usually it is stated that Strings can crash code on microcontrollers with only a small amount of RAM because the heap grows until it crashes into something else. The suggestion is that it won't happen on devices with a lot more RAM. Clearly it doesn't matter how much RAM there is, if the heap keeps growing then sooner or later it will hit other things in RAM, having more RAM just delays the inevitable.

The other thing that doesn't get discussed is the mechanism for program crash on a machine with a Harvard architecture. No amount of RAM corruption affects the program code because they exist in separate memory.

I was trying to give an example with containers on why the STL is not part of the configuration for AVRs.
Some features used in the underlying classes rely on specific C++ features that are memory hungry.

Underneath std::function, there is something known as type erasure — which allows it to store any callable object (like a lambda, functor, or function pointer) that matches a specific signature without needing to know the exact type at compile time.

It's done by defining a common base class that encapsulates the call operation and storing the callable in a derived class that implements this interface. This mechanism enables std::function to be versatile but also comes with trade-offs in memory and performance as @gfvalvo said. So if you have spare RAM, that's OK but on a UNO...

1 Like

It is worth noting that this is a disadvantage of the current implementation used by GCC, and not a fundamental problem of exceptions. If implemented properly, using exceptions for error handling actually has a lower memory footprint than using manual error handling using return codes and if statements: https://www.youtube.com/watch?v=BGmzMuSDt-Y

The STL is a C++ library that was developed by Alexander Stepanov in the early 90s that laid the foundation for generic programming in C++. It was a big deal, and many of its core principles made it into the C++ standard library, and some people still incorrectly refer to the C++ standard library as the STL.

std::function is part of the C++ standard library, not the STL. The C++ standard library is an integral part of the C++ language, as the name implies, and some language features cannot be used at all without the standard library. However, there is no implementation of the C++ standard library for the AVR platform. As discussed in my previous post, the reason for this is mainly economic, not technical.

The lack of the standard library is one of the main reasons why I no longer bother with AVR-based Arduinos for personal projects. Besides, many ARM chips are cheaper and more powerful anyway.

Overwriting program code is not the issue here. If your heap crashes into the stack, it's over, regardless of whether it's a Harvard or a von Neumann machine. The stack contains local variables and return addresses. Overwrite the local variables, and you'll end up with invalid indices, pointers etc., which will likely cause a crash, and if you overwrite the return address, you'll jump to some random address, also crashing the system.

It depends on the size of the small buffer in the implementation of std::function. If your function object is small enough, no dynamic allocation takes place, and the data is stored inside of the std::function object itself. IIRC, the small buffer usually isn't much larger than one pointer, though.

Only some features. If you use something like std::vector or std::string, that will obviously involve dynamic memory, whereas many other features like std::array or std::numeric_limits are perfectly safe.

2 Likes

The main problem with throwing and not catching the exceptions is that they restart the controller. By not being able to catch and properly handle the exceptions inside your code the controller will restart each time it runs out of memory.

If this isn't the case for a particular Arduino sketch and controller you are pretty much on the safe side by using STL classes.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.