联合成员的析构函数似乎被自动调用
Destructor of union member seems to be called automatically
我正在尝试实施标记联合。
我的理解是,在 C++ 联合中,非静态成员的非平凡(即不为空)析构函数从未被调用,因此我们必须自己调用它们.我就是这么做的:
#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;
}
然而,输出是:
C Ctor
C Dtor
C Dtor
意思是,C
析构函数被调用了两次,而不是只调用了一次。
这是怎么回事?如果您发现我的标记联合实施存在其他问题,请指出。
在
S(int type) : type(type) {
if (type == 0) {
u.c = C();
} else {
u.b = B();
}
}
因为你在构造函数的主体中,所以 u.c = C();
不是初始化而是赋值。这意味着您会看到为 C()
调用的构造函数,然后在表达式的末尾调用第一个析构函数调用来销毁该临时对象。我们可以通过添加
看到这一点
C& operator=(const C&) { std::cout << "operator=(const C&)\n"; return *this; }
到 C
将输出更改为
C Ctor
operator=(const C&)
C Dtor
C Dtor
然后第二次析构函数调用是当 s
超出 main 的范围时,它的析构函数是 运行.
请注意,代码有未定义的行为。联合不会激活构造函数用户提供的构造函数中的成员,所以当你这样做时
u.c = C();
您正在分配给一个尚未激活的对象。您无法修改不存在的对象。
在构造函数中创建 C:
的临时实例
u.c = C();
复制然后销毁。所以,前两行输出属于这个实例。
最后一行输出是您调用 ~S() 的结果。
除此之外,从 C++17 开始,您拥有标记联合的标准强大实现:https://en.cppreference.com/w/cpp/utility/variant
我正在尝试实施标记联合。
我的理解是,在 C++ 联合中,非静态成员的非平凡(即不为空)析构函数从未被调用,因此我们必须自己调用它们.我就是这么做的:
#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;
}
然而,输出是:
C Ctor
C Dtor
C Dtor
意思是,C
析构函数被调用了两次,而不是只调用了一次。
这是怎么回事?如果您发现我的标记联合实施存在其他问题,请指出。
在
S(int type) : type(type) {
if (type == 0) {
u.c = C();
} else {
u.b = B();
}
}
因为你在构造函数的主体中,所以 u.c = C();
不是初始化而是赋值。这意味着您会看到为 C()
调用的构造函数,然后在表达式的末尾调用第一个析构函数调用来销毁该临时对象。我们可以通过添加
C& operator=(const C&) { std::cout << "operator=(const C&)\n"; return *this; }
到 C
将输出更改为
C Ctor
operator=(const C&)
C Dtor
C Dtor
然后第二次析构函数调用是当 s
超出 main 的范围时,它的析构函数是 运行.
请注意,代码有未定义的行为。联合不会激活构造函数用户提供的构造函数中的成员,所以当你这样做时
u.c = C();
您正在分配给一个尚未激活的对象。您无法修改不存在的对象。
在构造函数中创建 C:
的临时实例u.c = C();
复制然后销毁。所以,前两行输出属于这个实例。 最后一行输出是您调用 ~S() 的结果。
除此之外,从 C++17 开始,您拥有标记联合的标准强大实现:https://en.cppreference.com/w/cpp/utility/variant