unrestricted union members lifetime during parent object construction

纵饮孤独 提交于 2021-01-28 11:00:39

问题


Normally you are responsible for lifetime of your unrestricted union members -- and typically you do it via in-place ctor/dtor calls. But, apparently, there is at least one case when compiler helps you -- in the code below, if object construction fails it's (previously constructed) union member gets automatically destroyed (at least in MSVC 2015), i.e. we never leak.

#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(...) {} }

Disclaimer: this code compiles on my MSVC 2015

Question -- is this guaranteed by standard and where it stipulates that?


回答1:


Quite the contrary: it's not supposed to happen!

[C++11: 9.5/8]: A union-like class is a union or a class that has an anonymous union as a direct member. A union-like class X has a set of variant members. If X is a union its variant members are the non-static data members; otherwise, its variant members are the non-static data members of all anonymous unions that are members of X.

[C++11: 15.2/2]: An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects (excluding the variant members of a union-like class), that is, for subobjects for which the principal constructor (12.6.2) has completed execution and the destructor has not yet begun execution. Similarly, if the non-delegating constructor for an object has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. If the object was allocated in a new-expression, the matching deallocation function (3.7.4.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object.

If Visual Studio is doing so, it's non-compliant; FWIW, GCC 6.3 seems to be also.

Note that the (current) C++17 wording is different and does permit what we're observing; this change appears to have been introduced by CWG issue #1866 in 2014, so it's likely that this is one of those times that the main compilers were "ahead of the game" and don't quite abide to the standard (despite -std flags).

So the answer is, no, the standard certainly doesn't guarantee it in MSVS 2015's case, though it will in future, C++17 versions of the software.



来源:https://stackoverflow.com/questions/43565457/unrestricted-union-members-lifetime-during-parent-object-construction

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!