首页 > 解决方案 > 不销毁属于联合成员的类类型的对象是否安全?

问题描述

我有这个例子:

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;

PS:我有这个来自 C++ 入门第 5 版第 19.6 章联合:

我们的析构函数检查被销毁的对象是否包含一个字符串。如果是这样,析构函数显式调用字符串析构函数(第 19.1.2 节,第 824 页)以释放该字符串使用的内存。如果联合拥有任何内置类型的成员,则析构函数没有工作可做。

“如果联合拥有任何内置类型的成员,析构函数就没有工作要做。” 我认为他可以添加:“或依赖于微不足道的析构函数的类类型”。你怎么看?

标签: c++classuniondestructor

解决方案


中给出的标准的确切措辞[basic.life]p6是:

对于类类型的对象,在重用或释放对象占用的存储空间之前,程序不需要显式调用析构函数;但是,如果没有显式调用析构函数,或者如果没有使用删除表达式 ([expr.delete]) 来释放存储空间,则不会隐式调用析构函数,并且任何依赖于析构函数有未定义的行为

(强调我的)

“取决于副作用”似乎很模糊,并且有很多关于堆栈溢出的问题讨论这个措辞。您的A类的析构函数似乎具有调用 I/O 函数的副作用,因此您似乎遇到了未定义的行为。

即使它不是 UB,如果它是std::vector, std::stringor std::fstream,您也会泄漏诸如内存或文件句柄之类的资源。这完全取决于类的析构函数(以及该类的任何成员)的作用。


由于“我的类A不通过原始指针管理资源”,它应该真的有一个微不足道的析构函数。在这种情况下,这一点没有实际意义,不调用析构函数也可以。


推荐阅读