c++ - 使用单个内存块来存储多个对象可以吗?

标签 c++ strict-aliasing

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

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保证足够大,内存+偏移量保证正确对齐,两个类的构造函数都声明为nothrow,并且两个类的析构函数都被调用内存释放后,这段代码是否引入了UB?使用此类代码我还会遇到哪些其他问题?

最佳答案

回答你的问题

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

不,没有

让我们先了解一些事情。

到底什么是别名?

别名是指多个左值引用同一内存位置(当您听到左值时,请考虑可以位于赋值左侧的事物(变量)),即可修改的事物。举个例子:

int anint;
int *intptr=&anint;

为什么首先要引入别名规则?

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

因此,在这种设置中,如果我想向某个对象发送消息,我必须有两个不兼容的指针指向同一 block 内存。

正如@Lightness正确提到的

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

Placement new 允许您在已分配的内存上构造对象。您可能希望这样做是为了优化(不要一直重新分配会更快),但您需要多次重新构造对象。如果您需要继续重新分配,分配比您需要的更多可能会更有效,即使您还不想使用它。

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 AliasingWhat uses are there for “placement new”?

关于c++ - 使用单个内存块来存储多个对象可以吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48975253/

相关文章:

c++ - 给定一组顶点,如何生成边数接近最少的强连通有向图?

c++ - 从基类指针调用派生类方法

c++ - 您能否/如何重新分配使用 placement new 创建的 C++ 对象?

位域结构的 C++ 严格别名规则

c - 严格别名和指向 union 字段的指针

c++ - 枚举名称作为函数

c++ - 结构/类数据对齐和填充算法?

c++ - 将围绕sockaddr_storage和sockaddr_in进行转换将破坏严格的别名

c - 通过示例了解限制限定符

c - 如何在未对齐的缓冲区中使用结构