Itachi Uchiwa
Itachi Uchiwa

Reputation: 3164

Is it safe not to destroy an object of a class type that is a member of a union?

I have this example:

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;

P.S: I have this from C++ primer 5th edition Chapter 19.6 unions:

Our destructor checks whether the object being destroyed holds a string. If so, the destructor explicitly calls the string destructor (§ 19.1.2, p. 824) to free the memory used by that string. The destructor has no work to do if the union holds a member of any of the built-in types.

"The destructor has no work to do if the union holds a member of any of the built-in types." I think he could add: "or of a class type which depends on the trivial destructor". What do you think?

Upvotes: 3

Views: 161

Answers (1)

Artyer
Artyer

Reputation: 40801

The exact wording of the standard given in [basic.life]p6 is:

For an object of a class type, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression ([expr.delete]) is not used to release the storage, the destructor is not implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.

(emphasis mine)

"depends on the side effects" seems pretty vague, and there are plenty of questions on stack overflow discussing this wording. Your A class's destructor seems to have the side effect of calling an I/O function, so it seems like you run into undefined behaviour.

Even if it wasn't UB, if it was a std::vector, std::string or std::fstream, you would leak resources like memory or file handles. It depends entirely on what the destructor of the class (and any members of that class) do.


Since "My class A doesn't manage a resource via a raw pointer", it should really have a trivial destructor. In which case, this point is moot and it is fine to not call the destructor.

Upvotes: 4

Related Questions