C++ 如果生命周期结束,是否允许隐式或显式重用对象存储?
考虑以下示例:C++ 如果生命周期结束,是否允许隐式或显式重用对象存储?,c++,language-lawyer,lifetime,c++17,C++,Language Lawyer,Lifetime,C++17,考虑以下示例: // create some storage alignas(int) char buffer[2 * sizeof(int)]; // new object of type int at the storage of buffer, the int pointed // to by p begins its lifetime here, buffer's lifetime is over int* p = new (buffer) int{42}; // some enti
// create some storage
alignas(int) char buffer[2 * sizeof(int)];
// new object of type int at the storage of buffer, the int pointed
// to by p begins its lifetime here, buffer's lifetime is over
int* p = new (buffer) int{42};
// some entirely unrelated int
int j = 17;
p
指向的新int
对象尚未使用的buffer
末尾的另一个存储是否允许重新打开堆栈,并被自动存储持续时间的后续对象隐式重用?换句话说,是否允许一致性实现具有&j==p+1
与此相关的是,明确重用其他存储是否是定义良好的行为
alignas(int) char buffer[2 * sizeof(int)];
int* p = new (buffer) int{42};
int* q = new (p+1) int{6};
也就是说,
p
和q
指向的int
s是否仍在其生命周期内 是的,很好
alignas(int) char buffer[2 * sizeof(int)];
在堆栈上分配8个字节
int* p = new (buffer) int{42};
int* q = new (p+1) int{6};
这些新操作符不分配内存来构造对象,而是使用缓冲区
但请注意,这些对象的生存期将是缓冲区变量的生存期。当缓冲区被销毁时,p&q引用的内存将被销毁
同样在一般情况下,您假设在销毁缓冲区之前手动调用析构函数
因此,“如果生命周期结束,是否允许隐式或显式重用对象存储?”问题的答案是No。当缓冲区的生命周期结束时,继续使用它的内存是不安全的,因为稍后它将用于其他堆栈变量
另外,我相信你明白,在你的情况下,像这样管理内存会更容易
int buffer[2];
int* p = &buffer[0];
int* q = &buffer[1];
编译器不必为堆栈中的每个变量使用唯一的内存区域,只要它能确定程序不能测量重复使用-例如,检查两个变量是否具有相同的地址,可能会导致编译器确保它们没有共享内存 范例
int a;
// do some stuff with a.
int b;
// do some stuff with b.
假设a和b都使用堆栈,它们可以共享地址,因为编译器可以告诉它们不同的用法
在堆栈上创建项是一条简单的指令
sub stackPointer, #AmountOfSpaceNeeded
在本例中,空间量不影响分配速度
在堆上创建项需要查找一些未使用的内存区域,或者在其中“映射”一些新的地址空间,并且需要使用堆的一条(或两条带帧指针的)指令的成本的许多倍
它还可能在内存检查器上产生误报,即对对象中可用的空闲内存量存在分歧
因此,优化使用堆中的一个位置以节省堆栈上的存储,如
规则,就像
规则一样如果编译器可以证明“p+1”不会被应用程序使用,那么如果它使用了该内存,您会如何注意(除了通过进行UB指针比较)呢?@Barry引用被替换为类型为T的对象o的生存期,当[…]对象占用的存储被释放时,或者被不嵌套在其他对象中的对象重用“存储”和“对象生命周期”以及“重用”的概念在我上一次标准研究时非常模糊,以至于无法使用,而不是“您知道它应该如何工作,它以这种方式工作”的解释。在实践中,自动重用存储将是疯狂的,而实际实现(如variant/any/std function/etc等代码)要求您可以获取一些存储,将其用于对象A,销毁对象A,然后将相同的存储重新用于对象B,而不仅仅是存储A。我知道C++17有一些修复,但。。。我不会抱希望的。@hyde嗯,
p->~int();新的(缓冲区)int[2]{1,2}代码>转到并使用缓冲区的第二部分。如果您需要重写j
@Yakk,这可能会令人惊讶。您不能将char*
分配给int*
。这回答了问题的第二部分,但忽略了问题的第一部分。OP的示例如何?对于变量j
?这是不正确的,因为对象具有明确的生存期。它们必须手动delete
d。它不绑定到缓冲区,但必须保持在缓冲区生存期内。