C++ 使用单个内存块存储多个对象可以吗?
我正在实现一种非常奇怪的结构,在这种结构中,我分配一个内存块,并在其中存储多个不同类型的对象:C++ 使用单个内存块存储多个对象可以吗?,c++,strict-aliasing,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(); auto memor
auto memory = reinterpret_cast<std::uintptr_t>(::operator new(size));
new(reinterpret_cast<void*>(memory)) Class1();
new(reinterpret_cast<void*>(memory + offset)) Class2();
auto memory=reinterpret_cast(::操作符新建(大小));
新的(重新解释(记忆))类别1();
新的(重新解释转换(内存+偏移量))类2();
我担心的是,这段代码是否违反了严格的别名规则
如果我将此代码重写如下:
void* memory = ::operator new(size);
new(memory) Class1();
new(reinterpret_cast<void*>(reinterpret_cast<char*>(memory) + offset)) Class2();
void*内存=::运算符新建(大小);
新(内存)类1();
新的(重新解释转换(重新解释转换(内存)+偏移量))类2();
假设
大小
保证足够大,内存+偏移量
保证正确对齐,两个类构造函数都声明nothrow,并且在内存释放时调用这两个类的析构函数,那么这段代码会引入UB吗?在回答您的问题时,我还可能遇到哪些其他问题
我担心的是,这段代码是否违反了严格的别名规则
不,它不是
让我们先了解一下
别名到底是什么?
别名是指当多个左值引用同一内存位置时(当您听到左值时,请考虑赋值左侧的内容(变量),即可修改的内容。例如:
int anint;
int *intptr=&anint;
为什么一开始就引入了别名规则?
在引入严格的别名之前,编译器必须生活在一种偏执状态中,buff的内容可以在任何时间、任何地点被任何人更改。因此,为了获得额外的性能优势,并且假设大多数人不键入双关语指针,引入了严格的别名规则
因此,在这种设置中,如果我想向某个对象发送消息,我必须有两个不兼容的指针指向同一块内存
正如@Lightness所说的那样
可以说,这就是为什么新的安置首先存在的原因
Placement new允许您在已分配的内存上构建对象。您可能希望这样做进行优化(不总是重新分配会更快),但您需要多次重新构造对象。如果您需要继续重新分配,那么即使您还不想使用它,分配比您需要的更多的资源可能会更有效
使用这样的代码我还可能遇到哪些其他问题?如果我把这段代码重写如下:
void* memory = ::operator new(size);
new(memory) Class1();
new(reinterpret_cast<void*>(reinterpret_cast<char*>(memory) + offset)) Class2();
void*内存=::运算符新建(大小);
新(内存)类1();
新的(重新解释转换(重新解释转换(内存)+偏移量))类2();
请放心,编译器将为您标记一些警告
注意:为了尽快发现别名问题,-fstrict-aliasing
应始终包含在GCC的编译标志中。否则,问题可能只在最难调试的最高优化级别可见
您可能想看看,假设您指的是多个对象(不是类),那么这一点也不奇怪-您正在实现一个内存池。我存储多个不同类型的对象。我不知道如何正确地表达标题,没关系。我看这个问题没有问题。要正确地回答这个问题,我必须比周日更深入地研究标准,但我希望你能得到你想要的。只是想让你放心,这是一件非常正常的事情(可以说,这就是为什么新的安置首先存在的原因)。