给出以下代码:
struct Bar {
Bar() { }
~Bar() { }
};
struct FooBase {
// No virtual destructor
};
struct Foo : FooBase {
Foo() : bar{} { }
union {
Bar bar;
};
};
int main() {
FooBase *p = new Foo;
static_cast<Foo *>(p)->bar.~Bar();
delete p;
}
我希望将Foo::bar
的有效期与其Foo
分开。
据我所知,delete p;
是明确定义的,当且仅当Foo
的析构函数是微不足道的。
由于Foo
只包含一个联合,并且不应该破坏它的bar
本身,看起来就是这样:非正式地说,析构函数什么都不做。
但是这个代码实际上是根据标准定义的吗?
答案 0 :(得分:1)
首先,[expr.delete]
对我来说不支持你声称“ delete p;
定义明确,当且仅当Foo的析构函数是微不足道的”。
在第一个备选方案(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应为动态类型的基类。要删除的对象,静态类型应具有虚拟析构函数或行为未定义。
由于静态类型为FooBase
,而动态类型为Foo
,我希望它是UB。
此外,(即使这不是UB)我认为Foo
的析构函数并非无足轻重。
[class.union]
类似联合的类是具有匿名联合作为直接成员的联合或类。类似联盟的
class X
有一组变体成员。如果X
是联合,则其变体成员是非静态数据成员;否则,其变体成员是X
成员的所有匿名联合的非静态数据成员。
因此Foo
是一个类似联合的类,bar
(类型为Bar
,其中有一个非平凡的析构函数)是变体成员。
[class.dtor]
4)如果一个类没有用户声明的析构函数,则析构函数被隐式声明为默认[...]。
5)如果
,class X
的默认析构函数被定义为已删除
X
是一个类似联合的类,其变体成员具有非平凡的析构函数[...]。
因此,我认为Foo
的隐式默认析构函数应该被定义为已删除,必须由用户提供。
(声明Foo q;
并看到编译失败。)
如果析构函数不是用户提供的,并且
,则析构函数是微不足道的
- [...]对于类的所有类型(或其数组)的非静态数据成员,每个这样的类都有一个简单的析构函数。
我会将该条款扩展到变体成员,因为它没有说“非变体数据成员”。
您可以在FooBase
中拥有虚拟析构函数,然后实现~Foo()
,而不包括bar.~bar();
,以便可以销毁bar
在~Foo()
中没有被再次破坏而前进。
但是我强烈反对它,因为在超出范围之前,你必须以某种方式为每个静态或动态~bar
调用Foo
。