Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does allocation of std::aligned_storage always have an offset?

When allocating an std::aligned_storage<2, 4096>::type on the heap I always get a pointer that is offset by 16 bytes (on x64; on x86 it is offset by 8 bytes). In other words, this:

#include <iostream>
#include <cstddef>

int main() {
    typedef std::aligned_storage<2, 4096>::type MemPage;

    MemPage* p_mp = new MemPage;

    std::cout << (void*)p_mp << std::endl;

    return 0;
}

gives me (for example)

0x72f010

although I would expect all the last three digits to be zero. When allocating the std::aligned_storage<>::type on the stack everything works as expected.

I use gcc-4.8.2 x86_64 on ubuntu 14.04.

like image 981
Toby Brull Avatar asked Nov 30 '14 20:11

Toby Brull


People also ask

Why is Aligned_storage deprecated in C ++ 23?

aligned_* are harmful to codebases and should not be used. At a high level: Using aligned_* invokes undefined behavior (The types cannot provide storage.) The guarantees are incorrect (The standard only requires that the type be at least as large as requested but does not put an upper bound on the size.)

What is std :: Aligned_storage?

struct aligned_storage; (since C++11) (deprecated in C++23) Provides the nested type type , which is a trivial standard-layout type suitable for use as uninitialized storage for any object whose size is at most Len and whose alignment requirement is a divisor of Align .

What is Alignof?

In C++11 the alignof operator used to returns the alignment, in bytes of the specified type. Syntax: alignof(type) Syntax Explanation: alignof: operator returns the alignment in byte, required for instances of type, which type is either complete type, array type or a reference type.


1 Answers

It's not quite clear how the alignment requirements transpose to storage allocated with new. The standard maintains in [expr.new] that

It is implementation-defined whether over-aligned types are supported (3.11).

[basic.align]/3:

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.6.2). A type having an extended alignment requirement is an over-aligned type.

Over-aligned types might not be supported by GCC, and the "non-support" of this might (instead of a compiler error) lead to the allocation function only returning storage aligned with the strictest fundamental alignment: sizeof(std::max_align_t). If the value of the latter is 16 on your machine, that would explain that the address is a multiple of 16.

Also note that, despite the fact that runtime allocation functions will have maximum supported alignments, operator new can basically not take desired alignments into account as it has no parameter that could take the corresponding value and pass it on to the runtime environments allocation function. This problem is known and subject of an EWG-issue.


Fun-fact: The above code is invoking UB. Consider the table in [meta.trans.ptr] that lists the requirements for aligned_storages second template argument:

Align shall be equal to alignof(T) for some type T or to default-alignment.

If no type T has an alignment of 4096 the requirement for the template argument is not fit. And what type would have an alignment of 212?

However, this is not important to the essence of the question. We can just use new with an own typedef.

like image 96
Columbo Avatar answered Oct 27 '22 00:10

Columbo