我一直在试图从此指针重用基类中分配的空间,而C ++ Standart不赞成。但是,该标准的措词似乎是错误的。它设置了一个条件“并且在被占用的对象的存储区被重用或释放之前”,但是显然可以在其自己的代码段中对其进行重用。我在哪里弄错了?
void B::mutate() {
new (this) D2; // reuses storage — ends the lifetime of *this!! REUSED AS WELL SO CONDITION SO RESTRICTIONS DON'T HOLD ANYMORE!
f(); // undefined behavior
在对象的生存期开始之前但已分配了该对象将要占用的存储空间之后41,或者在对象的生存期结束后以及该对象占用的存储空间被重用或释放之前,表示该对象的任何指针可以使用该对象将要或曾经位于的存储位置的地址,但只能以有限的方式使用。有关正在构造或销毁的对象,请参见[class.cdtor]。否则,此类指针将引用已分配的存储([basic.stc.dynamic.deallocation]),并且使用该指针时就像该指针的类型为void *一样,是定义良好的。允许通过此类指针进行间接访问,但生成的左值只能以有限的方式使用,如下所述。该程序在以下情况下具有未定义的行为:
(6.1) 该对象将是或曾经是具有非平凡析构函数的类类型,并且该指针用作delete-expression的操作数,
(6.2) 该指针用于访问对象的非静态数据成员或调用其非静态成员函数,或者
(6.3) 指针被隐式转换([conv.ptr])为指向虚拟基类的指针,或者
(6.4) 指针用作static_cast的操作数,除非转换是指向cv void的指针,或指向cv void的指针,然后是指向cv char,cv unsigned char或cv std :: byte([ cstddef.syn]),或
(6.5) 指针用作dynamic_cast的操作数。
[示例:
#include <cstdlib> struct B { virtual void f(); void mutate(); virtual ~B(); }; struct D1 : B { void f(); }; struct D2 : B { void f(); }; **void B::mutate() { new (this) D2; // reuses storage — ends the lifetime of *this f(); // undefined behavior** ... = this; // OK, this points to valid memory } void g() { void* p = std::malloc(sizeof(D1) + sizeof(D2)); B* pb = new (p) D1; pb->mutate(); *pb; // OK: pb points to valid memory void* q = pb; // OK: pb points to valid memory pb->f(); // undefined behavior, lifetime of *pb has ended }
答案 0 :(得分:3)
这样做的时候
f();
在成员函数中,您真正要做的是
this->f();
因此在示例中,当他们这样做
new (this) D2;
它结束this
所指向的事物指针的生命周期,并在该位置创建一个新的D2
。这使您认为this->f();
没问题,因为this
现在指向一个已经开始生命周期的对象,但是您忘记了this
是一个指向已经生命周期的对象的指针结束了。您不能使用它来引用您创建的新对象。
为了能够合法地调用f()
,您需要做的是捕获new
返回的指针,并使用它来访问新对象
void B::mutate() {
auto np = new (this) D2; // reuses storage — ends the lifetime of *this
f(); // undefined behavior**
np->f() // OK, np points to a valid object
... = this; // OK, this points to valid memory
}
答案 1 :(得分:2)
,但显然可以在自己的代码段中重复使用。
new (this) D2; // reuses storage — ends the lifetime of *this f(); // undefined behavior** ... = this; // OK, this points to valid memory
正确。由于存储已被重用,因此“其他”子句适用:
...否则,这样的指针将引用已分配的存储([basic.stc.dynamic.deallocation]),并且使用该指针时,就像该指针的类型为void *一样,都是定义良好的。
无法通过f()
调用void*
,因此该子句不允许这样做。否则,未定义生存期已结束的对象的调用成员函数(在析构函数之外)。
... = this;
可以用void*
完成。
请注意,(new (this) D2)->f()
的定义应明确。