使用两个类的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;
}输出:
yes-c
no-c
no-d
no-d
yes-d因此,uu将为联合调用正确的析构函数~no(),就好像它在构造联合时记录类型一样。这是怎么回事?
发布于 2019-02-16 13:12:09
union‘s永远不会“记住”哪个字段是活动的。
您的代码输出:
是的-c不-c不-d-d
您似乎将第3行(no-d)解释为对类的一个联合字段的析构函数调用,但这里不是这样的。~u()不会为y或n调用析构函数。
通过值将参数传递给构造函数,因此这一行是构造函数参数的析构函数调用。
发布于 2019-02-16 13:12:54
不,union并不“知道”它是活动成员。我们有std::variant做那份工作。您看到的是在构造函数中为union创建的临时结果。
当建立一个非平凡类型的联合时。随着程序变得更加复杂,您很可能陷入调用未定义行为的陷阱;std::variant很好地标记了您的联合。它将适当地管理生命周期
发布于 2019-02-16 16:53:58
union将足够大,足以容纳在union中声明的最大变量,以便可以将union中声明的任何变量类型的对象存储在其中。
但是,不跟踪union中存储的内容。存储在union中的任何对象都必须作为销毁包含union的对象的一部分显式销毁,就像存储在union中的任何对象都应显式地构造为构造包含union的对象的一部分一样。
程序员应该有某种机制来跟踪存储在union中的内容,并正确地处理任何构造和破坏操作。
程序员应该正确地访问union中存储的内容,方法是知道union中存储的内容,然后使用适当的union成员访问该对象。
用union演示程序
从其他答案的源开始,我扩展了该源代码,以演示struct的struct成员和struct的struct成员之间的区别。
在下面的代码中,我为包含union类的yes类和no类的类构造函数提供了代码。此外,我还为类u提供了默认构造函数、复制构造函数和赋值操作符。
除了您提供的两个结构,yes和no,我还提供了第三个struct,place,它不是在union中使用,而是另一个成员变量。
每个不同的类/结构在每次构造时都有一个静态计数器来计数。
为了正确处理赋值,我为struct of u提供了赋值操作符。默认赋值操作符相当于一个按位排列的副本,我希望保留每个实例的唯一标识符,以便正确地记录对构造和破坏的跟踪。
union vs struct ,并包含对象构造/销毁
注意,在此程序生成的输出中,当构造包含class的union时,将构造place结构,但是没有构造任何union成员。当包含class的union被销毁时,place结构将被销毁,但是没有一个union成员被破坏。
您还可以在输出中看到临时变量的构造、使用和解构。但是,请注意,当将临时值分配到union中时,不会调用析构函数。
所以在程序中有一个简单的作用域,有几个语句。
{
std::cout << "scope in" << std::endl;
std::cout << " create uu from n" << std::endl;
u uu(n);
std::cout << " assign y to uu" << std::endl;
uu = y;
std::cout << " assign n to uu" << std::endl;
uu = n;
std::cout << "scope out" << std::endl;
}我用与源的这一节相对应的几个注释来注释的输出部分是:
scope in
create uu from n
no-cc : 0 -> 1 --- create a temporary struct no for the call to construct
no-cc : 1 -> 2 --- assignment of temporary to union through copy construction
place-c : 1 --- construct non-union struct member
u-c - no: 1 place 1 tu: 2 tu_no: 2
no-d : 1 --- destruct the temporary passed to the constructor
assign y to uu
yes-cc : 0 -> 1 --- create a temporary struct yes for the assignment
yes-cc : 1 -> 2 --- assignment of temporary to union through copy construction
place-c : 2 --- construct non-union struct member
u-c - yes: 2 place 2 tu: 1 tu_yes: 2 --- construct temporary union member using yes version of the constructors
yes-d: 1 --- destruct the temporary used in assignment
u-= : 2 into 1 o.place 2 tu: 1 tu_yes: 2
u-d : 2 tu: 1 tu_yes: 2 --- destruct temporary union struct
place-d : 2 --- destruct non-union struct member
assign n to uu
no-cc : 0 -> 3 --- create a temporary struct no for the assignment
no-cc : 3 -> 4 --- assignment of temporary to union through copy construction
place-c : 3
u-c - no: 3 place 3 tu: 2 tu_no: 4 --- construct temporary union using no version of constructors
no-d : 3 --- destruct the struct no temporary
u-= : 3 into 1 o.place 3 tu: 2 tu_no: 4
u-d : 3 tu: 2 tu_no: 4 --- destruct the struct union temporary
place-d : 3
scope out接下来是在变量超出作用域时在作用域中创建的u实例的销毁,如下所示:
u-d : 1 tu: 2 tu_no: 2
place-d : 1注意,我们有一个no实例,一个实例标识符2,以及一个yes实例,实例标识符2,我们从未看到析构函数消息。这些是存储在union中的临时人员。注意,成员place的每个实例都是在解构其u容器时销毁的。
union 示例的源代码和输出
此演示程序的源代码:
// union_test.cpp : This file contains the 'main' function. Program execution begins and ends there.
// https://stackoverflow.com/questions/54723339/how-does-c-union-know-the-type-stored-in-it-and-which-destructor-to-call
#include "pch.h"
#include <iostream>
struct yes {
yes() : n(nc++) { std::cout << " yes-c: " << n << std::endl; }
yes(yes const& o) : n(nc++)
{
std::cout << " yes-cc : " << o.n << " -> " << n << '\n';
}
~yes() { std::cout << " yes-d: " << n << std::endl; }
int n = 0; // identifier number for specific instance
static int nc; // count of number of instances of this class created, instance identifier
};
struct no {
no() : n(nc++) { std::cout << " no-c : " << n << std::endl; }
no(no const& o) : n(nc++)
{
std::cout << " no-cc : " << o.n << " -> " << n << '\n';
}
~no() { std::cout << " no-d : " << n << std::endl; }
int n = 0; // identifier number for specific instance
static int nc; // count of number of instances of this class created, instance identifier
};
struct place {
place() : n(nc++) { std::cout << " place-c : " << n << std::endl; }
place(no const& o) : n(nc++)
{
std::cout << " place-cc : " << o.n << " -> " << n << '\n';
}
~place() { std::cout << " place-d : " << n << std::endl; }
int n = 0; // identifier number for specific instance
static int nc; // count of number of instances of this class created, instance identifier
};
struct u {
union {
yes y;
no n;
};
place p; // non-union to see construction/destruction of non-union.
int nu = 0; // identifier number for specific instance
int tu = 0; // indicator as to type currently in the union
static int nc; // count of number of instances of this class created, instance identifier
u() : nu(nc++) { std::cout << " u-c : " << nu << " place " << p.n << " tu: " << tu << std::endl; }
u(yes _y) :y(_y), nu(nc++), tu(1) {
std::cout << " u-c - yes: " << nu << " place " << p.n << " tu: " << tu;
switch (tu) {
case 0:
std::cout << std::endl;
break;
case 1:
std::cout << " tu_yes: " << y.n << std::endl;
break;
case 2:
std::cout << " tu_no: " << y.n << std::endl;
break;
default:
std::cout << "Unknown tu: " << tu << std::endl;
break;
}
}
u(no _n) :n(_n), nu(nc++), tu(2) {
std::cout << " u-c - no: " << nu << " place " << p.n << " tu: " << tu;
switch (tu) {
case 0:
std::cout << std::endl;
break;
case 1:
std::cout << " tu_yes: " << y.n << std::endl;
break;
case 2:
std::cout << " tu_no: " << y.n << std::endl;
break;
default:
std::cout << "Unknown tu: " << tu << std::endl;
break;
}
}
u(u const& o) : nu(nc++), tu(o.tu)
{
std::cout << "u-cc : " << o.nu << " -> " << nu << " tu: " << tu << " o.place " << o.p.n;
switch (tu) {
case 0:
std::cout << std::endl;
break;
case 1:
std::cout << " tu_yes: " << o.y.n << std::endl;
break;
case 2:
std::cout << " tu_no: " << o.n.n << std::endl;
break;
default:
std::cout << "Unknown tu: " << tu << std::endl;
break;
}
}
u & operator = (const u & o)
{
std::cout << "u-= : " << o.nu << " into " << nu << " o.place " << o.p.n << " tu: " << o.tu;
tu = o.tu;
switch (o.tu) {
case 0:
std::cout << std::endl;
break;
case 1:
std::cout << " tu_yes: " << o.y.n << std::endl;
break;
case 2:
std::cout << " tu_no: " << o.n.n << std::endl;
break;
default:
std::cout << "Unknown tu: " << tu << std::endl;
break;
}
return *this;
}
~u() {
std::cout << " u-d : " << nu << " tu: " << tu;
switch (tu) {
case 0:
std::cout << std::endl;
break;
case 1:
std::cout << " tu_yes: " << y.n << std::endl;
break;
case 2:
std::cout << " tu_no: " << n.n << std::endl;
break;
default:
std::cout << "Unknown" << std::endl;
break;
}
}
};
int yes::nc = 0;
int no::nc = 0;
int place::nc = 0;
int u::nc = 0;
int main()
{
std::cout << "create uu" << std::endl;
u xx;
std::cout << "create y" << std::endl;
yes y;
std::cout << "create n" << std::endl;
no n;
{
std::cout << "scope in" << std::endl;
std::cout << " create uu from n" << std::endl;
u uu(n);
std::cout << " assign y to uu" << std::endl;
uu = y;
std::cout << " assign n to uu" << std::endl;
uu = n;
std::cout << "scope out" << std::endl;
}
xx = y;
return 0;
}以及这个程序产生的输出。
create uu
place-c : 0
u-c : 0 place 0 tu: 0
create y
yes-c: 0
create n
no-c : 0
scope in
create uu from n
no-cc : 0 -> 1
no-cc : 1 -> 2
place-c : 1
u-c - no: 1 place 1 tu: 2 tu_no: 2
no-d : 1
assign y to uu
yes-cc : 0 -> 1
yes-cc : 1 -> 2
place-c : 2
u-c - yes: 2 place 2 tu: 1 tu_yes: 2
yes-d: 1
u-= : 2 into 1 o.place 2 tu: 1 tu_yes: 2
u-d : 2 tu: 1 tu_yes: 2
place-d : 2
assign n to uu
no-cc : 0 -> 3
no-cc : 3 -> 4
place-c : 3
u-c - no: 3 place 3 tu: 2 tu_no: 4
no-d : 3
u-= : 3 into 1 o.place 3 tu: 2 tu_no: 4
u-d : 3 tu: 2 tu_no: 4
place-d : 3
scope out
u-d : 1 tu: 2 tu_no: 2
place-d : 1
yes-cc : 0 -> 3
yes-cc : 3 -> 4
place-c : 4
u-c - yes: 4 place 4 tu: 1 tu_yes: 4
yes-d: 3
u-= : 4 into 0 o.place 4 tu: 1 tu_yes: 4
u-d : 4 tu: 1 tu_yes: 4
place-d : 4
no-d : 0
yes-d: 0
u-d : 0 tu: 1 tu_yes: -858993460
place-d : 0https://stackoverflow.com/questions/54723339
复制相似问题