C++ Attributes
Attributes is kind of a hidden language feature, but they do provide a nifty standardized way of specifying, well, attributes for various constructs that was previously only possible using compiler specific extensions.
Attributes
They were introduced with the C++11 revision of the C++ Standard and are described as (ยง7.6.1):
Attributes specify additional information for various source constructs such as types, variables, names, blocks, or translation units.
Traditionally each compiler have had their own way of specifying various
extensions in code, such as clang’s __attribute__()
, which can be used like
this for disabling optimizations for a function:
__attribute__(optnone)
void SomeFunction()
{
// ...
}
Microsoft’s compiler have a similar functionality in their __declspec
extension keyword.
What attributes does is basically to unfify these under a standardized construct
in the form of [[attribute-list]]
. The C++ Standard does provide a few
attributes, but most will be compiler specific and they are accessed using the
compiler specific namespace.
The attributes defined by the C++ Standard are1:
[[noreturn]]
[[carries_dependency]]
[[deprecated]]
[[deprecated("text")]]
Of those the [[deprecated]]
attribute is of particular interest. Every now and
then an API has to change, but it can’t just change over night as would break a
lot of client code. So there will be a phase where the old, deprecated,
functionality is still supported but is recommended not to be used anymore. We
can now easily let clients of our code know that:
// In library header file:
[[deprecated("to be replaced with more efficient Bar()")]]
void Foo();
// In client source code:
Foo();
Compiling that you’ll get an error2:
error: 'Foo' is deprecated: to be replaced with more efficient Bar()
[-Werror,-Wdeprecated-declarations]
This is great! It’s now immediately obvious to clients that they are using a deprecated function that may soon be removed. They don’t have to remember to go through documentation, changelogs, or release notes (or worse a compilation error for missing function) to find that out.
The compiler specific attributes are specified in the same way, only prefixed by a compiler specific namespace. For instance, the clang attribute above can be specified like this:
[[clang::optnone]]
void SomeFunction()
{
// ...
}
Unknown attributes are ignored but they do give warnings, and since you’re
compiling with all warnings on as errors you might want to disable that
particular one when compiling cross-platform code (that uses different attribute
namespaces and attributes). In clang you do that with: -Wno-deprecated-declarations
.
Alignment
With attributes also comes the ability to specify alignment for types or objects, and the ability to check alignment.
Alignments is primarily used for performance reasons to allow for optimal load and store operations for the CPU.
For example:
// 11 bytes. We'd like it to be aligned on a 16-byte boundary.
struct S {
char p[3];
char q[8];
};
S s;
printf("%p\n", (void*)&s);
printf("%ld\n", (long)&s & 15);
Outputs:
0x7fff5c402bc8
8
Unfortunately as can be seen by the output it’s not 16-byte aligned. This is
where alignas
comes in handy. If we change the definition of S to be:
struct alignas(16) S {
char p[3];
char q[8];
};
We get an output of:
0x7fff5a9d6bb0
0
Ah. Perfect. Except, that that check to see if we’re 16-byte aligned is not very
pretty. Luckily there’s a alingof
operator as well, and we can use it as:
// S defined as before.
printf("%ld\n", alingof(S));
Outputs:
16
Summary
Attributes provided a standardized way of accessing compiler specific
extensions. The standard [[deprecated]]
attribute is useful for letting
clients know about imminent API changes.
- C++ defines only a few attributes, most are compiler specific
alignas
lets you align object on a specific byte boundaryalignof
lets you check the alignment of a type
-
A few more are defined in the C++17 revision of the Standard:
[[fallthrough]]
,[[nodiscard]]
,[[maybe_unused]]
↩︎ -
Always compile with all warnings enabled and treat them as errors. See the Embracing Compiler Errors For Fun And Profit post for more details ↩︎