Как правило, вам на самом деле не нужно приводить указатель для проверки его битов, поскольку вы можете использовать индексы в буфере. Попробуйте использовать что-то вроде:
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <stdexcept>
#include <vector>
// in case your compiler doesn't support C++11 `alignof`,
// it's easy to implement
#define ALIGNOF(T) (sizeof(alignof_helper<T>) - sizeof(T))
// or in GNU C, although it provides __alignof__ anyway
#define ALIGNOF_C(T) ({ struct alignof_c_helper { char c; T data; }; sizeof(alignof_c_helper) - sizeof(T); })
// but of course, macros are EVIL.
template<class T>
struct alignof_helper
{
char c;
// implicit padding since data must be aligned
T data;
};
struct aligned_buffer
{
std::vector<uint8_t> vec;
size_t index;
aligned_buffer(size_t sz = 0)
: vec(sz)
, index(0)
{
}
template<class T>
T *get(size_t count=1)
{
// malloc() and ::operator new() return normally-aligned memory
static_assert(alignof(T) <= alignof(std::max_align_t), "no overaligned types without a special allocator");
size_t offset = this->index % alignof(T);
size_t start_index = this->index;
size_t new_index, asize;
if (offset)
{
start_index += alignof(T) - offset;
if (!start_index) // overflowed
throw std::length_error("how did you allocate that much? I'm impressed");
}
if (__builtin_mul_overflow(alignof(T), count, &asize) || __builtin_add_overflow(start_index, asize, &new_index))
{
throw std::length_error("ridiculous size");
}
if (new_index > this->vec.size())
{
throw std::length_error("insufficient reserved space");
}
this->index = new_index;
return reinterpret_cast<T *>(&this->vec[start_index]);
}
};
int main()
{
static_assert(alignof(int) == ALIGNOF(int), "C++98 version");
static_assert(alignof(int) == ALIGNOF_C(int), "GNU C statement-expression");
static_assert(alignof(int) == __alignof__(int), "GNU C keyword");
static_assert(alignof(int) == 4 && alignof(long long) == 8, "tests below assume a \"normal\" environment");
aligned_buffer buf(16);
*buf.get<char>() = 'A';
auto a = buf.get<int>(2);
a[0] = 123;
a[1] = 456;
try
{
buf.get<long long>();
throw std::logic_error("code is wrong I guess?");
}
catch (std::length_error& e)
{
}
// can still use the buffer
*buf.get<char>() = 'Z';
puts("everything is okay");
}
Изменение этого кода для безопасного изменения размера нижележащего буфера и, таким образом, беспокойство о недействительности указателя, оставлено в качестве упражнения для читателя.