> Starting in C++17, replacing the global allocator requires definitions for both plain new/delete and aligned new/delete.
Thanks for an interesting article; I wasn't aware of this... or at
least I don't remember deciding not to bother with it. I've written
global `new`/`delete` operators before in terms of `malloc`, I'm
wondering what is the right way to call an aligned `malloc` (from
C++), e.g. `aligned_alloc` or something else? Motivation for the
question is here:
https://github.com/possibly-wrong/mem-log/blob/master/mem_log.cpp#L127
Theoretically you'd call std::aligned_alloc, but this standard function is
unavailable on Windows because the CRT allocator doesn't support it. The
official documentation expresses it in odd wording: "the Windows operating
system doesn't support aligned allocations."
https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance
Obviously that's not literally true. Microsoft CRTs have _aligned_malloc,
but the catch is that it's paired with _aligned_free. It's a slightly more
expensive allocation through kind of "meta" allocator that accounts for
alignment. A replacement aligned new could be implemented using these two
non-standard functions. Compilers call aligned new/delete consistently,
and if you're in aligned delete you know you need to use _aligned_free.
This (or very similar) is the default definition of aligned new/delete on
Windows.
By "C++17 requires definitions" I mean that if you don't replace aligned
new/delete then over-aligned allocations won't use your custom allocator.
In my case, without a replacement some objects may not go in the arena and
will be leaked. (Though libstdc++ std::regex currently makes no aligned
allocations anyway.)
In your linked source aligned allocations will not be tracked or logged.
Such allocations are unusual, so it may not really matter. Consider: It
took until 2017 to even standardize it! People have only had some seven
years to put it into practice. On the other hand, I've come across wild
clang-format configs that toss alignas on every struct/class, and nearly
everything is over-aligned. Presumably it's for performance, but given the
_aligned_malloc situation above it's likely to have the opposite effect on
Windows.
If you're willing to assume newer compilers, you could simplify logging by
using sized delete, with a trapping plain delete (since there's no way to
"delete" it and cause a link failure). Instead of redundantly tracking
size at run time, you let the compiler tell you. Sized deallocation is now
default for GCC and MSVC. Currently Clang, or at least clang-cl, requires
some nudging (i.e. /Zc:sizedDealloc). I'm not saying you *should* do this,
just throwing it out as an option.
Correction to the last paragraph! I realized after I hit send: delete[] on
a trivially-destructible array will not use sized deallocation because the
compiler doesn't have access to the array length. For arrays that are not
trivially destructible the C++ implementation adds its own metadata (in
addition to any allocator metadata) to track array length so that it can
call the destructor on each element before calling delete[]. You'd still
need to track object size in your logger in order to handle these cases.