首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++联合如何知道存储在其中的类型以及调用哪一个析构函数?

C++联合如何知道存储在其中的类型以及调用哪一个析构函数?
EN

Stack Overflow用户
提问于 2019-02-16 13:03:01
回答 3查看 495关注 0票数 2

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

代码语言:javascript
运行
复制
#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;
}

输出:

代码语言:javascript
运行
复制
yes-c
no-c
no-d
no-d
yes-d

因此,uu将为联合调用正确的析构函数~no(),就好像它在构造联合时记录类型一样。这是怎么回事?

EN

回答 3

Stack Overflow用户

发布于 2019-02-16 13:12:09

union‘s永远不会“记住”哪个字段是活动的。

您的代码输出:

是的-c不-c不-d-d

您似乎将第3行(no-d)解释为对类的一个联合字段的析构函数调用,但这里不是这样的。~u()不会为yn调用析构函数。

通过值将参数传递给构造函数,因此这一行是构造函数参数的析构函数调用。

票数 2
EN

Stack Overflow用户

发布于 2019-02-16 13:12:54

不,union并不“知道”它是活动成员。我们有std::variant做那份工作。您看到的是在构造函数中为union创建的临时结果。

当建立一个非平凡类型的联合时。随着程序变得更加复杂,您很可能陷入调用未定义行为的陷阱;std::variant很好地标记了您的联合。它将适当地管理生命周期

票数 2
EN

Stack Overflow用户

发布于 2019-02-16 16:53:58

union将足够大,足以容纳在union中声明的最大变量,以便可以将union中声明的任何变量类型的对象存储在其中。

但是,不跟踪union中存储的内容。存储在union中的任何对象都必须作为销毁包含union的对象的一部分显式销毁,就像存储在union中的任何对象都应显式地构造为构造包含union的对象的一部分一样。

程序员应该有某种机制来跟踪存储在union中的内容,并正确地处理任何构造和破坏操作。

程序员应该正确地访问union中存储的内容,方法是知道union中存储的内容,然后使用适当的union成员访问该对象。

union演示程序

从其他答案的源开始,我扩展了该源代码,以演示structstruct成员和structstruct成员之间的区别。

在下面的代码中,我为包含union类的yes类和no类的类构造函数提供了代码。此外,我还为类u提供了默认构造函数、复制构造函数和赋值操作符。

除了您提供的两个结构,yesno,我还提供了第三个structplace,它不是在union中使用,而是另一个成员变量。

每个不同的类/结构在每次构造时都有一个静态计数器来计数。

为了正确处理赋值,我为struct of u提供了赋值操作符。默认赋值操作符相当于一个按位排列的副本,我希望保留每个实例的唯一标识符,以便正确地记录对构造和破坏的跟踪。

union vs struct ,并包含对象构造/销毁

注意,在此程序生成的输出中,当构造包含classunion时,将构造place结构,但是没有构造任何union成员。当包含classunion被销毁时,place结构将被销毁,但是没有一个union成员被破坏。

您还可以在输出中看到临时变量的构造、使用和解构。但是,请注意,当将临时值分配到union中时,不会调用析构函数。

所以在程序中有一个简单的作用域,有几个语句。

代码语言:javascript
运行
复制
{
    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;
}

我用与源的这一节相对应的几个注释来注释的输出部分是:

代码语言:javascript
运行
复制
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实例的销毁,如下所示:

代码语言:javascript
运行
复制
 u-d : 1  tu: 2  tu_no: 2
   place-d : 1

注意,我们有一个no实例,一个实例标识符2,以及一个yes实例,实例标识符2,我们从未看到析构函数消息。这些是存储在union中的临时人员。注意,成员place的每个实例都是在解构其u容器时销毁的。

union 示例的源代码和输出

此演示程序的源代码:

代码语言:javascript
运行
复制
// 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;
}

以及这个程序产生的输出。

代码语言:javascript
运行
复制
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 : 0
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54723339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档