C++ 当我们';重新开始覆盖内存对象的生存期是否已结束?
我无法自行解决以下问题: 假设我们以以下方式重用内存:C++ 当我们';重新开始覆盖内存对象的生存期是否已结束?,c++,constructor,destructor,C++,Constructor,Destructor,我无法自行解决以下问题: 假设我们以以下方式重用内存: 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的构造函数开始调用之前结
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)
。所以这是未定义的行为
对象a
的生命周期不会正式结束。你会得到这样的结果:
class A { int a; };
void* p = malloc(sizeof(A));
A* a1 = new (p) A();
A* a2 = new (p) A();
我认为,在同一内存中,您会得到类似于double的东西,称为析构函数,但这是编译器实现特有的东西。我不认为该标准对此有任何说明。相关章节(3.8)中的标准说 类型为T的对象的生存期在以下情况下结束: -如果T是具有非平凡析构函数(12.4)的类类型,则析构函数调用将启动,或者 -对象占用的存储被重用或释放
我的解释是,当
B
的成员初始化时,a
指向的对象的生命周期结束。在此之前,存储不会被重用。当您删除它时,a的生存期结束,而不是在此之前-因为强制两个不同的对象以这种方式占用相同的空间本身就是未定义的行为,并且绝对不建议您的编译器将该内存视为可重用的内存并覆盖b
如果您需要两个对象占用同一位置,例如:消息变体或您正在尝试编写自己的调试器,则应使用联合
类型
不建议您执行此类操作的另一个原因是,您将创建一个维护噩梦。e、 g.在以后的代码中,您可以:
b.b = 3
while (a.a > 0) {
b.b--;
}
只要您输入
B
的构造函数,a
就不再指向对象a
原因是,即使在对象构造函数的第一条指令之前,运行时就已经完成了VMT、基本子对象和成员初始化
另外,如果B
的构造函数没有因为异常而终止,那么内存已经被使用,并且最终出现在同一内存地址的另一个对象不再存在
换句话说就是不要那样做。。。在C++中,对象不仅仅是一堆字节,它们还有权利;例如,有权调用其析构函数;-) @RSahu a指向的对象的生命周期在您调用delete a之前不会结束;事实并非如此。因为3.8说,如果T是具有非平凡析构函数(12.4)的类类型,则T类型的对象的生存期结束,析构函数调用开始,或者对象占用的存储被重用或释放。@St.Antario:您这样做的目的是什么?首先,
新的A
只保证分配足够的内存来保存A
的实例,而不是B
的实例。Placement new(即new(a)B
的内容)不执行内存分配;它只是在a
指向的位置构造B
。您所拥有的是未定义的行为,根本不能保证工作。@Insilico我理解这是UB。但是我试图用这个标准来询问细节,并找到一个正式的解释。我不认为,这个标准确实说明了这一点。六羟甲基三聚氰胺六甲醚。。。假设我们必须以以下方式重用内存structc{C(){}~C(){};C*C=新的C;新的(c)c代码>。代码段不应产生UB。当新c的构造函数启动或新c的构造函数调用时,原始c的生存期结束?原始的c
不会被删除。因此,如果您在C
中分配了任何资源(例如)文件,则在调用delete
之前不会释放它们。然后你重用这个内存块,这也会导致UB,因为两个对象在同一个内存块中初始化(请参阅)。然后你重用这个内存块,这也会导致UB。我不同意,因为标准中有相关的章节。看见