C++ union如何知道存储在其中的类型以及要调用的析构函数?

Det*_*ing 2 c++ union

使用union两个类,在这个简单的示例中,它会union记住存储在其中的最后一个类,并为该对象调用正确的析构函数:

#include <iostream>

using std::cout;
using std::endl;

struct yes{
    yes(){cout<<"yes-c"<<endl;}
    ~yes(){cout<<"yes-d"<<endl;}
};
struct no{
    no(){cout<<"no-c"<<endl;}
    ~no(){cout<<"no-d"<<endl;}
};
struct u{
    union{
        yes y;
        no n;
    };
    u(yes _y):y(_y){}
    u(no _n):n(_n){}        
    ~u(){}
};


int main() {
    yes y;
    no n;
    {
    u uu(n);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

yes-c
no-c
no-d
no-d
yes-d
Run Code Online (Sandbox Code Playgroud)

因此,uu将为~no()union 调用正确的析构函数,就像它在构造union时记录类型一样.这是如何运作的?

Som*_*ude 5

简短回答:事实并非如此.

如果你添加一个拷贝构造函数,no你会看到实际上有三个 no对象被创建,但只有两个被破坏.

首先,您创建对象n.然后,当您通过值将其传递给u构造函数时,它将被复制一次到_n参数中.也就是说_n然后对象被复制到该uu.n构件.

析构是构造函数中的_n参数,也是u函数中的n对象main.


这是您的程序稍加修改,以添加复制构造函数并跟踪no对象:

#include <iostream>

struct yes{
    yes(){std::cout<<"yes-c"<<std::endl;}
    ~yes(){std::cout<<"yes-d"<<std::endl;}
};
struct no{
    no(){std::cout<<"no-c : "<<n<<std::endl;}
    no(no const& o)
        : n(o.n + 1)
    {
        std::cout << "no-cc : " << o.n << " -> " << n << '\n';
    }

    ~no(){std::cout<<"no-d : "<<n<<std::endl;}
    int n = 0;
};
struct u{
    union{
        yes y;
        no n;
    };
    u(yes _y):y(_y){}
    u(no _n):n(_n){}
    ~u(){}
};

int main()
{
    yes y;
    no n;
    {
        u uu(n);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果没有优化或copy-elision,这将创建输出

yes-c
no-c : 0
no-cc : 0 -> 1
no-cc : 1 -> 2
no-d : 1
no-d : 0
yes-d

输出no-c : 0用于n在main函数中创建对象.

输出no-cc : 0 -> 1用于复制到u构造函数参数_n.

输出no-cc : 1 -> 2用于将参数复制_n到联合n对象中.

输出no-d : 1是对_n参数的破坏.

输出no-d : 0是函数中n对象的破坏main.