mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-27 18:02:17 +03:00
exceptions: optionally enforce c++ standards (#6333)
* exceptions: 3 choices: legacy, std::new never returns 0, or exceptions enabled * arduino_new (doc, example, array)
This commit is contained in:
@ -215,3 +215,75 @@ using FPSTR would become...
|
||||
String response2;
|
||||
response2 += FPSTR(HTTP);
|
||||
}
|
||||
|
||||
C++
|
||||
----
|
||||
|
||||
- About C++ exceptions, ``operator new``, and Exceptions menu option
|
||||
|
||||
The C++ standard says the following about the ``new`` operator behavior when encountering heap shortage (memory full):
|
||||
|
||||
- has to throw a ``std::bad_alloc`` C++ exception when they are enabled
|
||||
|
||||
- will ``abort()`` otherwise
|
||||
|
||||
There are several reasons for the first point above, among which are:
|
||||
|
||||
- guarantee that the return of new is never a ``nullptr``
|
||||
|
||||
- guarantee full construction of the top level object plus all member subobjects
|
||||
|
||||
- guarantee that any subobjects partially constructed get destroyed, and in the correct order, if oom is encountered midway through construction
|
||||
|
||||
When C++ exceptions are disabled, or when using ``new(nothrow)``, the above guarantees can't be upheld, so the second point (``abort()``) above is the only ``std::c++`` viable solution.
|
||||
|
||||
Historically in Arduino environments, ``new`` is overloaded to simply return the equivalent ``malloc()`` which in turn can return ``nullptr``.
|
||||
|
||||
This behavior is not C++ standard, and there is good reason for that: there are hidden and very bad side effects. The *class and member constructors are always called, even when memory is full* (``this == nullptr``).
|
||||
In addition, the memory allocation for the top object could succeed, but allocation required for some member object could fail, leaving construction in an undefined state.
|
||||
So the historical behavior of Ardudino's ``new``, when faced with insufficient memory, will lead to bad crashes sooner or later, sometimes unexplainable, generally due to memory corruption even when the returned value is checked and managed.
|
||||
Luckily on esp8266, trying to update RAM near address 0 will immediately raise an hardware exception, unlike on other uC like avr on which that memory can be accessible.
|
||||
|
||||
As of core 2.6.0, there are 3 options: legacy (default) and two clear cases when ``new`` encounters oom:
|
||||
|
||||
- ``new`` returns ``nullptr``, with possible bad effects or immediate crash when constructors (called anyway) initialize members (exceptions are disabled in this case)
|
||||
|
||||
- C++ exceptions are disabled: ``new`` calls ``abort()`` and will "cleanly" crash, because there is no way to honor memory allocation or to recover gracefully.
|
||||
|
||||
- C++ exceptions are enabled: ``new`` throws a ``std::bad_alloc`` C++ exception, which can be caught and handled gracefully.
|
||||
This assures correct behavior, including handling of all subobjects, which guarantees stability.
|
||||
|
||||
History: `#6269 <https://github.com/esp8266/Arduino/issues/6269>`__ `#6309 <https://github.com/esp8266/Arduino/pull/6309>`__ `#6312 <https://github.com/esp8266/Arduino/pull/6312>`__
|
||||
|
||||
- New optional allocator ``arduino_new``
|
||||
|
||||
A new optional global allocator is introduced with a different semantic:
|
||||
|
||||
- never throws exceptions on oom
|
||||
|
||||
- never calls constructors on oom
|
||||
|
||||
- returns nullptr on oom
|
||||
|
||||
It is similar to arduino ``new`` semantic without side effects
|
||||
(except when parent constructors, or member constructors use ``new``).
|
||||
|
||||
Syntax is slightly different, the following shows the different usages:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
// with new:
|
||||
|
||||
SomeClass* sc = new SomeClass(arg1, arg2, ...);
|
||||
delete sc;
|
||||
|
||||
SomeClass* scs = new SomeClass[42];
|
||||
delete [] scs;
|
||||
|
||||
// with arduino_new:
|
||||
|
||||
SomeClass* sc = arduino_new(SomeClass, arg1, arg2, ...);
|
||||
delete sc;
|
||||
|
||||
SomeClass* scs = arduino_newarray(SomeClass, 42);
|
||||
delete [] scs;
|
||||
|
Reference in New Issue
Block a user