c++ - 不销毁属于联合成员的类类型的对象是否安全?
问题描述
我有这个例子:
struct A{
A(){std::cout << "A's def-ctor\n";}
~A(){std::cout << "A's dtor\n";}
A(A const&){std::cout << "A's copy-ctor\n";}
A& operator = (A const&){std::cout << "A's copy-assign op\n"; return *this; }
};
struct Foo{
Foo() : curMem_(INT), i_(0){}
~Foo(){
if(curMem_ == CLS_A) // If I comment out this line then what happens?
a_.~A();
}
enum {INT, CHAR, CLS_A, BOOL} curMem_;
union{
int i_;
char c_;
A a_;
bool b_;
};
};
Foo f;
f.curMem_ = Foo::CLS_A;
f.a_ = A();
f.curMem_ = Foo::BOOL;
f.b_ = true;
我们知道类默认析构函数不知道联合类型的类成员的哪个成员是活动的,这就是为什么我们确实需要定义析构函数的输出版本。所以联合的类类型的成员数据不会被自动销毁。那么如果我不明确调用联合的那些类类型成员的析构函数会发生什么?
如果我在析构函数中注释该行
Foo
或删除析构函数本身会发生什么?它是未定义的行为吗?我的类
A
不通过原始指针管理资源,那么当它的对象是 a 的成员时,为什么我还要费心显式调用它的析构函数union
?谢谢!
PS:我有这个来自 C++ 入门第 5 版第 19.6 章联合:
我们的析构函数检查被销毁的对象是否包含一个字符串。如果是这样,析构函数显式调用字符串析构函数(第 19.1.2 节,第 824 页)以释放该字符串使用的内存。如果联合拥有任何内置类型的成员,则析构函数没有工作可做。
“如果联合拥有任何内置类型的成员,析构函数就没有工作要做。” 我认为他可以添加:“或依赖于微不足道的析构函数的类类型”。你怎么看?
解决方案
中给出的标准的确切措辞[basic.life]p6
是:
对于类类型的对象,在重用或释放对象占用的存储空间之前,程序不需要显式调用析构函数;但是,如果没有显式调用析构函数,或者如果没有使用删除表达式 ([expr.delete]) 来释放存储空间,则不会隐式调用析构函数,并且任何依赖于析构函数有未定义的行为。
(强调我的)
“取决于副作用”似乎很模糊,并且有很多关于堆栈溢出的问题讨论这个措辞。您的A
类的析构函数似乎具有调用 I/O 函数的副作用,因此您似乎遇到了未定义的行为。
即使它不是 UB,如果它是std::vector
, std::string
or std::fstream
,您也会泄漏诸如内存或文件句柄之类的资源。这完全取决于类的析构函数(以及该类的任何成员)的作用。
由于“我的类A
不通过原始指针管理资源”,它应该真的有一个微不足道的析构函数。在这种情况下,这一点没有实际意义,不调用析构函数也可以。
推荐阅读
- android - 如何在 Xamarin 中设置当前视图
- python-3.x - 数据框中父节点的总和值
- javascript - 在 js 中以编程方式测量页面加载
- c++ - 程序第一次运行完美,但第二次从二进制文件中读取类时想知道 seg 错误?
- c# - 将逗号分隔的字符串分组为范围组 2 维数组
- python - 如何将分钟添加到时间数据?
- r - 使用 dplyr 进行过滤、表格和排序?
- python - 如何为我的 NN 模型正确地塑造我的数据?
- tensorflow - Colab 最近更新导致错误:Tensor 对象仅在启用 Eager Execution 时才可迭代
- haskell - 在haskell中对我的数据子集进行模式匹配