A std::vector<char>
contains a pointer to some heap-allocated buffer.
Considering memory alignment issues, is the allocated buffer returned by the memory allocation guaranteed to be correctly aligned for only the type char
, or will it be aligned to some common value, such as 4 or 8 bytes? (Or is it unspecified?)
To explain by way of example, the default allocator is new
. Calling new
may return an arbitrary memory address. But is it really arbitrary?
T
used in std::vector<T>
? (This seems the most likely of the options.)The reason for asking this question is that I want to know whether I can safely re-interpret the bytes contained within this block of memory as other types, for example float
, double
, uint64_t
, etc.
Going the other way, the situation is more obvious. (I think - do correct me.)
For example, if we were to ask for a std::vector<uint64_t>
, then the pointer returned by the memory allocation, and held by the std::vector
object, would be 8-byte aligned.
So it would be safe to read and write data as:
char*
float
double
unsigned short int
However, if the allocation for std::vector<char>
can return a memory address of 1025
(decimal), then this is clearly not guaranteed to be aligned correctly at any offset if re-interpreted as any type larger than 1 byte wide.
I think my understanding is correct here, but of course do let me know in the comments if any of this doesn't quite make sense or fit together correctly.
I may have found an answer to this, but I am not sure how to interpret what I have read.
From:
This function is required to return a pointer suitably aligned to point to an object of the requested size.
But what does this mean?
For an object of width 1 byte, this would seemingly suggest any address value is acceptable.
For an object of width 2 bytes, it would suggest any even value address is acceptable.
For 4 bytes, any multiple of 4. And for 8 bytes any multiple of 8.
But what about other values? There is no instruction to load a 3 byte value from memory in x86, as far as I am aware. What happens if you request new[T]
where T
is a 3 byte wide struct
?
While it technically doesn't seem to be guaranteed, I'm fairly sure no implementation is going to give you an under-aligned pointer from a std::vector<char>
.
The default operator new
returns a memory aligned to __STDCPP_DEFAULT_NEW_ALIGNMENT__
, and while I can't find any guarnatees that this is >= alignof(std::max_align_t)
, any sane implementation would do it this way.
There's also a version of operator new
that takes std::align_val_t
, and while its intent is to support larger alignments, there's no guarantee that std::allocator
doesn't call it for smaller alignments too, though a sane implementation probably either wouldn't do it, or if it would, the call would still ensure at least __STDCPP_DEFAULT_NEW_ALIGNMENT__
alignment.
A big part of why I expect this to work in practice is that std::align_val_t
and the overaligned operator new
were added relatively recently, in C++17. Before that you had to have __STDCPP_DEFAULT_NEW_ALIGNMENT__ >= alignof(std::max_align_t)
for new
to work sanely, and std::vector<char>
had to give you a pointer aligned at least to __STDCPP_DEFAULT_NEW_ALIGNMENT__
, so I doubt the implementations are going to suddenly drop this guarantee.