Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/eclipse/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用单个内存块存储多个对象可以吗?_C++_Strict Aliasing - Fatal编程技术网

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的编译标志中。否则,问题可能只在最难调试的最高优化级别可见


您可能想看看,假设您指的是多个对象(不是类),那么这一点也不奇怪-您正在实现一个内存池。我存储多个不同类型的对象。我不知道如何正确地表达标题,没关系。我看这个问题没有问题。要正确地回答这个问题,我必须比周日更深入地研究标准,但我希望你能得到你想要的。只是想让你放心,这是一件非常正常的事情(可以说,这就是为什么新的安置首先存在的原因)。