当我们开始覆盖内存时,对象的生命周期是否已经结束?

When we're starting to overwrite memory has lifetime of an object has ended yet?

本文关键字:是否 周期 生命 结束 对象 开始 我们 覆盖 内存      更新时间:2023-10-16

我无法独自解决以下问题:

假设我们以以下方式重用内存:

struct A 
{ 
    int a;
    A(){ }
    ~A(){ }
};
struct B : A 
{ 
    int b;
    B(){ }
    ~B(){ }
};
A *a = (A*) malloc(sizeof(A) + sizeof(B));
B *b = new (a) B; //Constructor of B is calling

a引用的对象的生存期在B的构造函数开始调用之前已经结束,还是在B的构造函数完成时已经结束?

您尝试使用placement-new运算符来初始化b。此运算符不首先调用类A的析构函数(a),而是将一个新的析构因子初始化到a指向的内存中。这是有问题的(如注释中所述),因为sizeof(B)大于sizeof(A),并且在指针a处只分配了sizeof(A)。所以这是未定义的行为。

对象CCD_ 12的生存期不会正式结束。你会得到这样的东西:

class A { int a; };
void* p = malloc(sizeof(A));
A* a1 = new (p) A();
A* a2 = new (p) A();

我认为,在同一个内存上会得到类似double的析构函数,但这是编译器实现特定的。我不认为,标准确实说明了这一点。

一旦输入B的构造函数,a就不再指向对象A

原因是,甚至在对象的构造函数的第一条指令之前,运行时就已经完成了VMT、基本子对象和成员初始化。

此外,如果B的构造函数没有因为异常而终止,那么内存已经被使用,并且最终出现在同一内存地址的另一个对象不再存在。

换句话说,就是不要那样做。。。在C++中,对象不仅仅是一堆字节,而且它们有权限;例如调用其析构函数的权利;-)

相关章节(3.8)中的标准规定,

T类型对象的寿命在以下情况下结束:

-如果T是具有非平凡析构函数(12.4)的类类型,则析构函数调用启动,或者

-对象占用的存储器被重新使用或释放。

我的意思是,当B的成员初始化时,a指向的对象的生命周期结束。在此之前,存储不会被重复使用。

当您删除它时,而不是之前,它的生存期就结束了-因为以这种方式强迫两个不同的对象占用相同的空间本身就是未定义的行为,绝对不建议您的编译器可能会也可能不会将该内存视为可重用并覆盖b。

如果您需要两个对象占据相同的位置,例如:Message Variants,或者您正在尝试编写自己的调试器,那么您应该使用union类型。

不建议你做这种事情的另一个原因是,你会制造一场维护噩梦。例如,在代码的后面,您可能会有:

b.b = 3
while (a.a > 0) {
   b.b--;
}
相关文章: