C++ 父对象构造期间的无限制联合成员生存期

C++ 父对象构造期间的无限制联合成员生存期,c++,c++11,unions,C++,C++11,Unions,通常情况下,您要对不受限制的工会成员的生命周期负责——通常通过就地ctor/dtor调用来完成。但是,显然,至少有一种情况是编译器可以帮助您——在下面的代码中,如果对象构造失败,它的(先前构造的)联合成员将自动销毁(至少在MSVC 2015中是这样),即我们从不泄漏 #include <string> struct CanThrow { CanThrow() { throw 0; } }; struct A { A() : str{} {} // not

通常情况下,您要对不受限制的工会成员的生命周期负责——通常通过就地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(...) {} }
#包括
结构悬臂
{
CanThrow(){throw 0;}
};
结构A
{
A():str{}{}//注意,我们在这里没有显式地调用str dtor
~A(){str.~basic_string();}
联合{std::string str;};
悬臂ct;
};
int main(){try{A;}catch(…){}
免责声明:此代码在我的MSVC 2015上编译

问题——标准是否保证了这一点?它在哪里规定了这一点?

恰恰相反:这是不应该发生的

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

[C++11:15.2/2]:
任何存储持续时间的对象,如果其初始化或销毁因异常而终止,则将对其所有完全构造的子对象(不包括类联合的变量成员)执行析构函数。,也就是说,对于主构造函数(12.6.2)所针对的子对象已完成执行,而析构函数尚未开始执行。类似地,如果对象的非委托构造函数已完成执行,并且该对象的委托构造函数存在异常,则将调用该对象的析构函数。如果在新表达式中分配了对象,则会调用匹配的释放函数(3.7.4.2、5.3.4、12.5)(如果有)以释放对象占用的存储

如果VisualStudio正在这样做,那么它是不符合要求的;FWIW

请注意,(当前)C++17的措辞是不同的,并且允许我们观察到的内容,因此,这很可能是主编译器“领先于游戏”并且不完全遵守标准的时候之一(尽管有
-std
标志)


所以答案是,不,在MSVS 2015的情况下,标准当然不能保证它,尽管它在将来会保证,C++17版本的软件。

你怎么知道它被破坏了?析构函数中的断点它肯定发生在MSVC2015中。使用~basic_string()GCC中的断点签入调试器也被破坏——在main()中添加try/catch-around构造。您的示例失败,因为转义的异常不会解除堆栈。很抱歉,我应该添加它。@C.M:呃,很好的一点,lol,那么是的,除非我误读了什么,否则这两个功能都会被破坏。看起来整个功能完全。。。为什么我在语言最基本的构建块中不断遇到这样的问题?顺便说一句,编译器正在尝试做正确的事情——在这种情况下不调用dtor是一种语言缺陷。。。如果我在我的类中有三个这样的联合,并试图在ctor初始值设定项列表中构造所有这些联合——我无法判断在出现异常时需要销毁哪一个联合。