父对象构造期间不受限制的联合成员生命周期

时间:2017-04-22 22:48:51

标签: c++ c++11 unions

通常,您对无限制工会成员的有效期负责 - 通常您通过就地ctor / dtor电话来执行此操作。但是,显然,至少有一种情况是编译器帮助你 - 在下面的代码中,如果对象构造失败,它的(先前构建的)联合成员会被自动销毁(至少在MSVC 2015中),即我们从不泄漏。

#include <string>

struct CanThrow
{
    CanThrow() {  throw 0;  }
};

struct A
{
    A() : str{} {}    // note that we don't explicitly call str dtor here
    ~A() { str.~basic_string(); }

    union { std::string str; };
    CanThrow ct;
};

int main() { try{ A a; } catch(...) {} }

免责声明:此代码在我的MSVC 2015上编译

问题 - 这是由标准保证的吗?它规定了什么?

1 个答案:

答案 0 :(得分:1)

恰恰相反:它应该发生!

  

[C++11: 9.5/8]: 类似于联盟的类是一个联合或具有匿名联合作为直接成员的类。类似联合的类X具有一组变体成员。如果X是联合,则其变体成员是非静态数据成员;   否则,其变体成员是X成员的所有匿名联合的非静态数据成员。

     

[C++11: 15.2/2]: 任何存储持续时间的对象,其初始化或销毁由异常终止,将为其所有完全构造的子对象执行析构函数(不包括类似联合的类的变体成员)< / strong>,即对于主构造函数(12.6.2)已完成执行且析构函数尚未开始执行的子对象。类似地,如果对象的非委托构造函数已完成执行,并且该对象的委托构造函数以异常退出,则将调用该对象的析构函数。如果对象是在new-expression中分配的,则调用匹配的释放函数(3.7.4.2,5.3.4,12.5)(如果有的话)以释放对象占用的存储空间。

如果Visual Studio正在这样做,那么它是不合规的; FWIW,GCC 6.3 seems to be also

请注意,(当前)C ++ 17的措辞是不同的,并且允许我们观察的内容; this change appears to have been introduced by CWG issue #1866 in 2014,所以很有可能这是主要编译器在游戏之前的时间之一&#34;并且不要完全遵守标准(尽管-std标志)。

所以答案是, no ,标准肯定不能在MSVS 2015的情况下保证,尽管将来会有C ++ 17版本的软件