Does the alignas specifier work with 'new'?
Before C++17, if your type's alignment is not over-aligned, then yes, the default new
will work. "Over-aligned" means that the alignment you specify in alignas
is greater than alignof(std::max_align_t)
. The default new
will work with non-over-aligned types more or less by accident; the default memory allocator will always allocate memory with an alignment equal to alignof(std::max_align_t)
.
If your type's alignment is over-aligned however, your out of luck. Neither the default new
, nor any global new
operator you write, will be able to even know the alignment required of the type, let alone allocate memory appropriate to it. The only way to help this case is to overload the class's operator new
, which will be able to query the class's alignment with alignof
.
Of course, this won't be useful if that class is used as the member of another class. Not unless that other class also overloads operator new
. So something as simple as new pair<over_aligned, int>()
won't work.
C++17 adds a number of memory allocators which are given the alignment of the type being used. These allocators are used specifically for over-aligned types (or more specifically, new-extended over-aligned types). So new pair<over_aligned, int>()
will work in C++17.
Of course, this only works to the extent that the allocator handles over-aligned types.
Why does the alignas specifier throw an error on Clang?
Well, the grammar you cited states that an attribute-specifier-seq that occurs in a type-specifier-seq has to occur after all type-specifiers. Therefore, you'd have to put it here in order to have the attributes appertain to the preceding int
according to [dcl.type]/1:
new int attribute-specifier-seq [2];
You'd have to put it here in order to have the attributes appertain to the array type according to [expr.new]/6:
new int [2] attribute-specifier-seq;
You could also combine them: you can have different attributes for the array type and for the element type. But I don't think the grammar allows you to place the attributes before the int
.
As for the specific issue of an alignment specifier: the standard neither explicitly permits nor explicitly forbids applying an alignment specifier to a type-specifier or type-id ([dcl.align]/1). Clang seems to interpret the standard as forbidding it. GCC seems to interpret the standard as allowing it; however, since the standard does not specify any semantics for the alignment specifier when it appertains to a type, a warning is issued. Consider:
struct S {
int x alignas(16);
int alignas(16) y;
};
Here, S::x
will have an alignment requirement of 16 but the alignment specifier for S::y
is meaningless. So if you write int alignas(16) y
, it makes sense for GCC to warn you so you realize you put it in the wrong place.
To force the allocated memory to be aligned on a 16-byte boundary, use the placement syntax to explicitly call the overload of operator new
that takes an alignment argument:
int* x = new (std::align_val_t(16)) int [2];
Memory alignment : how to use alignof / alignas?
Alignment is a restriction on which memory positions a value's first byte can be stored. (It is needed to improve performance on processors and to permit use of certain instructions that works only on data with particular alignment, for example SSE need to be aligned to 16 bytes, while AVX to 32 bytes.)
Alignment of 16 means that memory addresses that are a multiple of 16 are the only valid addresses.
alignas
force alignment to the required number of bytes. You can only align to powers of 2: 1, 2, 4, 8, 16, 32, 64, 128, ...
#include <cstdlib>
#include <iostream>
int main() {
alignas(16) int a[4];
alignas(1024) int b[4];
printf("%p\n", a);
printf("%p", b);
}
example output:
0xbfa493e0
0xbfa49000 // note how many more "zeros" now.
// binary equivalent
1011 1111 1010 0100 1001 0011 1110 0000
1011 1111 1010 0100 1001 0000 0000 0000 // every zero is just a extra power of 2
the other keyword
alignof
is very convenient, you cannot do something like
int a[4];
assert(a % 16 == 0); // check if alignment is to 16 bytes: WRONG compiler error
but you can do
assert(alignof(a) == 16);
assert(alignof(b) == 1024);
note that in reality this is more strict than a simple "%" (modulus) operation. In fact we know that something aligned to 1024 bytes is necessarily aligned to 1, 2, 4, 8 bytes but
assert(alignof(b) == 32); // fail.
So to be more precise, "alignof" returns the greatest power of 2 to wich something is aligned.
Also alignof is a nice way to know in advance minimum alignment requirement for basic datatypes (it will probably return 1 for chars, 4 for float etc.).
Still legal:
alignas(alignof(float)) float SqDistance;
Something with an alignment of 16 then will be placed on the next available address that is a multiple of 16 (there may be a implicit padding from last used address).
Practical use cases for alignof and alignas C++ keywords
A common use case for the alignas
specifier is for the scenario where you want to pass multiple objects between different threads through a queue (e.g., an event or task queue) while avoiding false sharing. False sharing will result from having multiple threads competing for the same cache line when they are actually accessing different objects. It is usually undesirable due to performance degradation.
For example – assuming that the cache line size is 64 bytes – given the following Event
class:
struct Event {
int event_type_;
};
The alignment of Event
will correspond to the alignment of its data member, event_type_
. Assuming that the alignment of int
is 4 bytes (i.e., alignof(int)
evaluates to 4), then up to 16 Event
objects can fit into a single cache line. So, if you have a queue like:
std::queue<Event> eventQueue;
Where one thread pushes events into the back of the queue, and another thread pulls events from the front, we may have both threads competing for the same cache line. However, by properly using the alignas
specifier on Event
:
struct alignas(64) Event {
int event_type_;
};
This way, an Event
object will always be aligned on a cache line boundary so that a cache line will contain an Event
object at most. Therefore two or more threads will never be competing for the same cache line when accessing distinct Event
objects (if multiple threads are accessing the same Event
object, they will obviously compete for the same cache line).
What is the correct usage/syntax for the c++17 alignas() specifier for dynamically allocated arrays of fundamental types?
While C++17 does have the means for operator new
to be given an alignment for the memory it allocates, there is no mechanism in C++ to specify the alignment for memory allocated by a new
expression outside of the alignment of the type being allocated. That is, if you perform a new T
or new T[]
, the alignment of the allocated pointer will be alignof(T)
. C++17 added alignment-based operator new
allocators, which allows them to support over-aligned types.
This is fine if you have control over T
and can specify its alignment at definition time via alignas
. But if you're using someone else's type or a fundamental type like double
, you can't change the alignment of those types. So there's no way to directly use a new
expression to allocate such memory.
You will have to use ::operator new
directly to allocate sufficient memory at the desired alignment, and then use placement-new
to actually create the objects there. Of course, placement-new
on arrays has a number of issues.
I suspect this compiles only because alignas
is considered an attribute and it is grammatically legal to shove an attribute before the []
in a new
expression. It isn't intended to actually work, as there is no statement in the section on new
expressions that allows it to get the alignment of the allocation from anything other than alignof(T)
.
Where can I use alignas() in C++11?
You cannot apply an alignment to a typedef
. In the C++ model of alignment specifiers, the alignment is an inseparable part of the type itself, and a typedef
does not create a new type (it only provides a new name for an existing type) so it is not meaningful to apply an alignment specifier in a typedef
declaration.
From [dcl.align] (7.6.2)p1:
An alignment-specifier may be applied to a variable or to a class data member [...]. An alignment-specifier may also be applied to the declaration or definition of a class (in an elaborated-type-specifier (7.1.6.3) or class-head (Clause 9), respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration
or enum-head, respectively (7.2)).
These are the only places where the standard says an alignment-specifier (alignas(...)
) may be applied. Note that this does not include typedef
declarations nor alias-declarations.
Per [dcl.attr.grammar] (7.6.1)p4:
If an attribute-specifier-seq that appertains to some entity or statement contains an attribute that is not allowed to apply to that entity or statement, the program is ill-formed.
This wording was intended to apply to alignas
as well as the other forms of attribute that may appear within an attribute-specifier-seq, but was not correctly updated when alignment switched from being a "real" attribute to being a different kind of attribute-specifier-seq.
So: your example code using alignas
is supposed to be ill-formed. The C++ standard does not currently explicitly say this, but it also does not permit the usage, so instead it currently would result in undefined behavior (because the standard does not define any behavior for it).
alignas specifier vs __attribute__(aligned), c++11
It seems from the GCC support status, alignment support is not fully supported in gcc 4.7, but it is for gcc 4.8. alignas
is also listed as a newly supported feature from the 4.8 release page.
Also, from the alignment support proposal (3.11):
A fundamental alignment is represented by an alignment less than or equal to the greatest alignment supported by the implementation in all contexts, which is equal to alignof(std::max_align_t) (18.1).
An extended alignment is represented by an alignment greater than
alignof(std::max_align_t). It is implementation-defined whether any extended
alignments are supported and the contexts in which they are supported (7.1.6). A type
having an extended alignment requirement is an over-aligned type.
And from the same document (7.1.6):
if the constant expression evaluates to an extended alignment and the implementation
does not support that alignment in the context of the declaration, the program is illformed
That might be part of the answer too. I don't have access to the full standard at the moment, someone should be able to confirm this.
As for the difference between __attribute__(aligned)
and alignas
, i don't think they are semantically different, but one is just a compiler extension while the other is fully defined by the standard.
To answer your last question, alignas
is only defined for:
alignas ( constant-expression )
alignas ( type-id )
C++ class specifier alignas option via template
You can do it like this:
template <size_t alignment = 0>
class alignas(alignment) C {
// ...
};
Now C<>
will have the default alignment for its definition (since alignas(0)
is ignored) while you could use e.g. C<16>
to force an alignment of 16.
Why does the C++ standard allow std::max_align_t and __STDCPP_DEFAULT_NEW_ALIGNMENT__ to be inconsistent?
There are two layers of over-aligned types in C++17: extended and new-extended. std::max_align_t
defines the largest alignment that is not extended, and __STDCPP_DEFAULT_NEW_ALIGNMENT__
defines the largest alignment that is not new-extended.
New-extended alignment, as the name suggests, is about the alignment of things you allocate with new
.
Basically, the regular operator new
will return memory suitable for any object up to the new-extended alignment size. Any greater alignment prefers the use of operator new
overloads that specify the alignment of the type being created. And of course, are conditionally supported just like over-aligned types in general. The same goes for the operator delete
calls to destroy the memory associated with such types.
What Visual Studio is saying is that the maximum alignment that is not considered over-aligned is 8-byte, but the alignment for memory allocated by operator new
is 16-byte.
This means that when overruling the
new
operators, you are forced to align everything on at least 16 bytes, even if 8 bytes would be sufficient.
Essentially, yes. There's no way to request that the implementation tell you what alignment is being requested with the raw operator new/delete
overloads.
Now, you can, on an object-by-object basis, overload that object's operator new
to invoke the alignment-specific operator new
directly. But you can't make the compiler do so.
Related Topics
How to Debug C++11 Code with Unique_Ptr in Ddd (Or Gdb)
Returning VS. Using a Reference Parameter
Cocreateinstance Returning E_Nointerface Even Though Interface Is Found
Read and Write on Serial Port in Ubuntu with C/C++ and Libserial
What Are Google Test, Death Tests
Addresses of Identical Function Template Instantiations Across Compilation Units
Can Virtual Functions Be Constexpr
Enumerate Com Object (Idispatch) Methods Using Atl
Sdl/C++ Opengl Program, How to Stop Sdl from Catching Sigint
C++ Is It Necessary to Delete Dynamically Allocated Objects at the End of the Main Scope
How to Add Code at the Entry of Every Function
Cannot Open Windows.H in Microsoft Visual Studio
What Are the Different Character Sets Used For
Makefile Enforce Library Dependency Ordering
Why How to Implicitly Convert an Int Literal to an Int * in C But Not in C++