Skip to content

Commit 3eb2556

Browse files
committed
doc
1 parent 283ab5d commit 3eb2556

File tree

1 file changed

+36
-64
lines changed

1 file changed

+36
-64
lines changed

doc/reference.rst

Lines changed: 36 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -219,28 +219,13 @@ using FPSTR would become...
219219
C++
220220
----
221221

222-
- About C++ ``operator new`` and return value and its replacement ``new0<>()``
223-
224-
In short, it is preferred for stability to use new `new0` instead of `new`:
225-
226-
.. code:: cpp
227-
228-
SomeClass* sc = new0<SomeClass>(arg1, arg2, ...);
229-
// abort() is never called, an exception is not thrown even if they are enabled
230-
if (sc == nullptr)
231-
{
232-
// failed allocation, handle here
233-
}
234-
else
235-
{
236-
// use sc
237-
}
222+
- About C++ exceptions, ``operator new``, and Exceptions menu option
238223

239224
The C++ standard says the following about the ``new`` operator behavior when encountering heap shortage (memory full):
240225

241-
- has to throw a ``std::bad_alloc`` C++ exception
226+
- has to throw a ``std::bad_alloc`` C++ exception when they are enabled
242227

243-
- throw an unhandled exception, which means calling ``abort()``
228+
- will ``abort()`` otherwise
244229

245230
There are several reasons for the first point above, among which are:
246231

@@ -250,59 +235,46 @@ C++
250235

251236
- guarantee that any subobjects partially constructed get destroyed, and in the correct order, if oom is encountered midway through construction
252237

253-
When C++ exceptions are disabled, or when using ``new(nothrow)``, the above guarantees can't be upheld, so the second point above is the only viable solution.
238+
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.
254239

255-
Historically in Arduino environments, ``new`` is overloaded to simply return the equivalent ``malloc()`` which in turn can return ``nullptr``. In other cores, and up to our core version 2.5.2, that is considered as acceptable.
240+
Historically in Arduino environments, ``new`` is overloaded to simply return the equivalent ``malloc()`` which in turn can return ``nullptr``.
256241

257-
However, 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.
242+
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``).
243+
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.
244+
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.
245+
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.
258246

259-
As of core 2.6.0, we are sticking to the C++ standard. There are two clear cases when ``new`` encounters oom:
247+
As of core 2.6.0, there are 3 options: legacy (default) and two clear cases when ``new`` encounters oom:
248+
249+
- ``new`` returns ``nullptr``, with possible bad effects or immediate crash when constructors (called anyway) initialize members (exceptions are disabled in this case)
260250

261-
- C++ exceptions are disabled (default build): ``new`` causes an exception, which in turn calls ``abort()`` and will "cleanly" crash, because there is no way to honor memory allocation or to recover gracefully.
251+
- C++ exceptions are disabled: ``new`` calls ``abort()`` and will "cleanly" crash, because there is no way to honor memory allocation or to recover gracefully.
252+
253+
- C++ exceptions are enabled: ``new`` throws a ``std::bad_alloc`` C++ exception, which can be caught and handled gracefully.
254+
This assures correct behavior, including handling of all subobjects, which guarantees stability.
255+
256+
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>`__
257+
258+
- New optional allocator ``new0``
259+
260+
A new optional global allocator is introduced with a different semantic:
261+
262+
- never throws exceptions on oom
263+
264+
- never calls constructors on oom
265+
266+
- returns nullptr (without side effects - excepted when parent constructors, or member constructors use ``new``)
267+
268+
It is similar to arduino ``new`` semantic without side effects.
262269

263-
- C++ exceptions are enabled (menu option): ``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.
264-
265-
To allow previous behavior, a new optional global allocator is introduced with a different semantic. It is similar to ``new`` but will return ``nullptr`` without side effects (if ``std::new`` is not used in constructors), as expected in arduino world.
266-
267270
Syntax is slightly different, the following shows the different usages:
268-
271+
269272
C++ standard behavior (as of 2.6.0):
270-
271-
.. code:: cpp
272-
273-
SomeClass* sc = new SomeClass(arg1, arg2, ...);
274-
// sc is always valid and not nullptr, no check necessary
275-
// abort() gets called (crash dump, reboot) if oom,
276-
// or a C++ std::bad_alloc exception is thrown when available
277-
278-
Old behavior (until 2.5.2):
279-
273+
280274
.. code:: cpp
281-
275+
276+
// with new:
282277
SomeClass* sc = new SomeClass(arg1, arg2, ...);
283-
// abort() is never called, an exception is not thrown even if they are enabled
284-
if (sc == nullptr)
285-
{
286-
// failed allocation, handle here, possible bad hidden effects
287-
}
288-
else
289-
{
290-
// use sc
291-
}
292-
293-
Alternate behavior (as of 2.6.0):
294-
295-
.. code:: cpp
296-
278+
279+
// with new0
297280
SomeClass* sc = new0<SomeClass>(arg1, arg2, ...);
298-
// abort() is never called, an exception is not thrown even if they are enabled
299-
if (sc == nullptr)
300-
{
301-
// failed allocation, handle here
302-
}
303-
else
304-
{
305-
// use sc
306-
}
307-
308-
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>`__

0 commit comments

Comments
 (0)