Destructor of union member seems to be called automatically

三世轮回 提交于 2020-06-27 15:37:08

问题


I'm attempting to implement a tagged union.

My understanding was that in a C++ union, the non-trivial (i.e. not empty) destructors of non-static members are never called, thus we have to call them ourselves. That's what I did:

#include <iostream>

class C {
public:
  C() {
    std::cout << "C Ctor" << std::endl;
  }
  ~C() {
    std::cout << "C Dtor" << std::endl;
  }
};

class B {
public:
  B() {
    std::cout << "B Ctor" << std::endl;
  }
  ~B() {
    std::cout << "B Dtor" << std::endl;
  }
};

struct S {
  int type;

  union U {
    C c;
    B b;

    U() {

    }

    ~U() {}
  } u;

  S(int type) : type(type) {
    if (type == 0) {
      u.c = C();
    } else {
      u.b = B();
    }
  }

  ~S() {
    if (type == 0) {
      u.c.~C();
    } else {
      u.b.~B();
    }
  }
};

int main() {
  S s(0);
  return 0;
}

However, the output is:

C Ctor
C Dtor
C Dtor

Meaning, the C destructor is being called twice, instead of just once.

What is going on? And if you notice additional issues with my tagged union implementation, please point them out.


回答1:


In

S(int type) : type(type) {
    if (type == 0) {
      u.c = C();
    } else {
      u.b = B();
    }
  }
  

Since you are in the body of the constrcutor, u.c = C(); is not initialization but is instead assigment. That means you see the constructor called for C(), and then at the end of the expression the first destructor call is called to destroy that temporary. We can see this by adding

C& operator=(const C&) { std::cout << "operator=(const C&)\n"; return *this; }

to C which changes the output to

C Ctor
operator=(const C&)
C Dtor
C Dtor

Then the second destructor call is when s goes out of scope in main and its destructor is ran.


Do note that as is, the code has undefined behavior. Unions do not activate a member in the constructor user provided constructor you wrote so when you do

u.c = C();

you are assigning to an object that is not yet alive. You can't modify an object that isn't alive.




回答2:


In your constructor you create the temporary instance of C:

u.c = C();

which is copied and then destructed. So, first 2 lines of output belong to this instance. And the last output line is result of your ~S() call.

Besides this, beginning from C++17 you have standard powerful implementation of tagged union: https://en.cppreference.com/w/cpp/utility/variant



来源:https://stackoverflow.com/questions/62555368/destructor-of-union-member-seems-to-be-called-automatically

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