How to call the overloaded aligned new and delete operators in `C++17`?
Asked Answered
A

3

6

From cppreference we can see several new overloads of new and delete, as well as new[] and delete[] were added. I can't find any examples of usage with the new aligned overloads, neither on cppreference nor anywhere else. I've experimented with them for quite some time now and I can't find out how to trigger these aligned dynamically allocated calls. Anyone has any idea, kindly share an example.

Autonomous answered 4/11, 2018 at 20:15 Comment(3)
Show us your experiments. What is wrong with them? Since C++17, new expression should handle over-aligned types automatically by using a special version of operator new.Recursion
It important to ensure your compiler has support for this feature: en.cppreference.com/w/cpp/compiler_supportPlumbic
@AntonyPeacock Note that the corresponding row is called "Dynamic memory allocation for over-aligned data (P0035R4)".Recursion
P
7

You need to specify the align as keyword on your type and then just call new and delete as normal. I have put together an article with examples about it here: https://github.com/Twon/Alignment/blob/master/docs/alignment_in_C%2B%2B.md. An example is:

#include <memory>

int main() {
    class alignas(16) float4 {
        float f[4];
    }; 

    std::unique_ptr<float4 > aligned_vec4(std::make_unique<float4 >());
}

And an example with the Intel compiler which currently make this feature available via the aligned_new extension header: https://software.intel.com/en-us/articles/aligned-operator-new-support-in-intel-c-compiler

Plumbic answered 4/11, 2018 at 20:22 Comment(3)
aligned_new is not a header file from the C++ Standard. In C++17, new expression will use a special version of operator new for over-aligned types automatically. AFAIK, until C++17, there is no portable way how to dynamically allocate memory for over-aligned objects. Usually, posix_memalign or similar platform-specific functions were used.Recursion
Yes, you are correct. The aligned_new header was an extension proposed in open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r4.html. The Intel Compiler supports aligned_new from version 15 on wards. However while this proposal was accepted into the language the aligned_new head appears not to have made it into the final draft of the C++17 standard: open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf. Updating my answer to reflect this.Plumbic
Thanks. Note that P0035R4 does nor propose <aligned_new> header file. It only mentions this header provided by Intel and then uses this name as exemplary in a note about backward compatibility.Recursion
M
2

It’s on cppreference, just buried a few links deep: https://en.cppreference.com/w/cpp/language/new

new(2,f) T; // calls operator new(sizeof(T), 2, f)
        // (C++17) or operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f)

More information on it: https://www.bfilipek.com/2017/06/cpp17-details-clarifications.html Looks like you actually use the alignas keyword and it will automatically call the new new.

Mak answered 4/11, 2018 at 20:19 Comment(3)
Note that in this example, 2 and f has nothing to do with alignment.Recursion
For over-aligned types, new expression will use the new operator new that reflects their alignment (just to be precise about "new new").Recursion
@DanielLangr Yes, 2 and f are user-defined parameters to the custom placement new function. Just doing new T would suffice to call the align_val_t variant of new, provided T specifies alignment larger/stricter than the default alignment (__STDCPP_DEFAULT_NEW_ALIGNMENT__) as shown in the accepted answer (class alignas(16) float4 { float f[4]; }).Whitelaw
S
2

I guess the question was how to call an overloaded new explicitly, whereas all answers so far advised how to do it implicitly.

My solution (floats aligned to 256-byte boundaries):

auto q = new (std::align_val_t(256)) float;
auto p = new (std::align_val_t(256)) float[10];

Explanation

We go to https://en.cppreference.com/w/cpp/language/new ("new expression') and navigate to section "Placement new":

If placement_params are provided, they are passed to the allocation function as additional arguments

That's it!

Well, almost. Here: https://en.cppreference.com/w/cpp/memory/new/operator_new we read:

These allocation functions are called by new-expressions to allocate memory in which new object would then be initialized. They may also be called using regular function call syntax.

I was intrigued by the possibility of calling operator new using function call syntax. I don't think anyone does it like this. Let's try:

auto r = operator new (sizeof(float), std::align_val_t(256));
auto s = operator new[] (sizeof(float)*10, std::align_val_t(256)); // don't do it!!!

Ugly and dangerous, especially in the array-like version, as it does not have a place for the argument corresponding to the number of requested elements -- all it needs is the number of bytes to allocate, which may require taking into account some alignment overhead.

Sparling answered 17/12, 2020 at 10:56 Comment(3)
operator new is different from the new expression. The former only allocates memory (often it's a wrapper for malloc) whereas the latter calls operator new itself and then constructs the object in the memory address returned.Autonomous
Good point. This would explain why people don't use "function call syntax" to construct objects.Sparling
To answer the second part of the question, #include <new>, then call ::operator delete[](ptr, std::align_val_t(256));Rileyrilievo

© 2022 - 2024 — McMap. All rights reserved.