【问题标题】:Can an union's destructor be trivial?联合的析构函数可以是微不足道的吗?
【发布时间】:2017-02-23 12:50:34
【问题描述】:

给定以下代码:

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 本身,因此看起来就是这样:通俗地说,该析构函数什么都不做。

但是这段代码真的是按照标准定义好的吗?

See it live on Coliru

【问题讨论】:

  • 1.) 只有一个成员变量的未命名联合是奇怪的。 2.) 如果您不确定,那么很可能是 UB。我会质疑你的假设,即 delete p 在这里定义良好。
  • @knivil 我am质疑它是否定义明确;)
  • 啊,,,我虽然你问其他奇怪的事情,如Foos 析构函数或分配给基类指针而不是多态的。

标签: c++ language-lawyer undefined-behavior unions


【解决方案1】:

首先,[expr.delete] 对我来说不支持您的说法,即“delete p; 是明确定义的当且仅当 Foo 的析构函数是微不足道的”。

在第一种选择(delete object)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应为动态类型的基类。要删除的对象,并且静态类型应具有虚拟析构函数或行为未定义。

由于静态类型是 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 中有一个虚拟析构函数,然后在不包括bar.~bar(); 的情况下实现~Foo(),这样可以提前销毁bar 而不会在@ 中再次销毁它987654341@.

但我强烈建议不要这样做,因为您必须以某种方式为每个静态或动态 Foo 调用 ~bar,然后才能超出范围。

【讨论】:

  • VS2015: 警告 C4624: 'Foo': 析构函数被隐式定义为已删除
  • 如果我通过基类指针销毁Foo,是否使用了析构函数?
  • @knivil:如果基类没有虚拟析构函数,它就是 UB。该实现可能使用也可能不使用 Foo 的析构函数。
猜你喜欢
  • 2013-09-11
  • 2014-05-13
  • 2020-07-18
  • 2012-04-09
  • 2015-12-20
  • 2010-09-06
  • 2018-05-13
  • 1970-01-01
  • 2017-05-09
相关资源
最近更新 更多