使用单个内存块存储多个对象是否可以?

Is it ok to use a single memory chunk to store multiple objects?

我正在实现一个非常奇怪的结构,我在其中分配一个内存块并在其中存储多个不同类型的对象:

auto memory = reinterpret_cast<std::uintptr_t>(::operator new(size));
new(reinterpret_cast<void*>(memory)) Class1();
new(reinterpret_cast<void*>(memory + offset)) Class2();

我的问题,这段代码是否违反了严格的别名规则?

如果我将这段代码重写如下:

void* memory = ::operator new(size);
new(memory) Class1();
new(reinterpret_cast<void*>(reinterpret_cast<char*>(memory) + offset)) Class2();

鉴于 size 保证足够大,memory + offset 保证正确对齐,两个 class 构造函数都声明为 nothrow,并且两个 class 的析构函数es在内存释放时被调用,这段代码是不是引入了UB?使用此类代码我还会遇到哪些其他问题?

在回答你的问题时

My concern, does this code violates the strict aliasing rules?

不对

我们先了解一下。

什么是别名?

别名是指多个左值引用相同的内存位置(当您听到左值时,想想可以在赋值的 left-hand 一侧的事物(变量)),即可修改的。例如:

int anint;
int *intptr=&anint;

为什么一开始就引入了别名规则?

在引入严格的别名之前,编译器不得不生活在一种偏执的状态中,任何人都可以随时随地更改 buff 的内容。因此,为了获得额外的性能优势,并假设大多数人没有 type-pun 指针,引入了严格的别名规则。

所以在这种设置中,如果我想向某物发送消息,我必须有两个不兼容的指针指向同一块内存。

如@Lightness 所述正确

arguably, it's why placement new exists in the first place

Placement new 允许您在已分配的内存上构造一个对象。你可能想这样做是为了优化(不是一直 re-allocate 更快)但是你需要多次 re-construct 一个对象。如果您需要保留 re-allocating,分配比您需要的更多的资源可能更有效,即使您还不想使用它。

What other problems I can encounter with such code? And What if I rewrite this code as follows:

 void* memory = ::operator new(size);
    new(memory) Class1();
    new(reinterpret_cast<void*>(reinterpret_cast<char*>(memory) + offset)) Class2();

请放心,编译器会标记一些警告。

注意: 为了尽快发现别名问题,-fstrict-aliasing 应该始终包含在 GCC 的编译标志中。否则问题可能只在最难调试的最高优化级别可见。

你可能想看看 Endianness, Understanding C/C++ Strict Aliasing and What uses are there for “placement new”?