工会的破坏者可以琐碎吗?

时间:2017-02-23 12:50:34

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

给出以下代码:

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 个答案:

答案 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