🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c++
Article #3225

class.union questions

#3225
From: Dirk Becker
Date: Sat, 03 Feb 1996 17:22
135 lines
5581 bytes
Hello, C++ gurus!

In Section 9.6.1 Unions [class.union] there is a large collection of
restrictions on the union itself and on candidate member classes.
I would like to ask for reasons of several of them:

a)  "A union shall not have base classes. A union shall not be used as
     a base class."

This prevents any construction like the following, where one would
like to extend the union contained in some base class:

class GenericInterpreter {
    union opcode {
        short tag;
        struct { short tag; short data; } op1;
        struct { short tag; char* data; } op2;
    };
};

class SpecialInterpreter : public GenericInterpreter {
    union opcode : public GenericInterpreter::opcode {
        struct { short tag; long  data; } op3;
        struct { short tag; float data; } op4;
    };
};

b) "An object of a class with a non-trivial default constructor
    (_class.ctor_), a non-trivial copy constructor (_class.copy_),
    a non-trivial destructor (_class.dtor_), or a non-trivial copy
    assignment operator (_over.ass_, _class.copy_) cannot be a member
    of a union,"

This is a major reduction of the restrictions found in ARM, where all
kinds of constructors or assignment operators were excluded. Here is
also a note to give the explanation by the assumption, any member
functions and especially assignments would usually expect a correctly
constructed object.

The quoted WP sequence tries its best to exclude virtual function
tables from the union members, which is just fine. But through the
non-trivialness you also exclude _any_ custom make of the copy
constructor and assignment operator.
So you can have any special assignment operator or constructor for
your member objects, any but the most common and useful ones.

Another sample:

class longlong { ... };
struct opcode {
    short tag;
    union {
        short     op1;
        long      op2;
        longlong  op3;
    } data;
};

If you are lucky to have some native long long datatype, then this
would be legal code. If you already had to implement your own
class longlong, now you lost the chance to use it (here).

c) "A union can be thought of as a class"

Here you accept the implications of 12.8.8 and 12.8.13 on implicitly
defined copy constructor and copy assignment. The already trivial
copy constructor/assignment of the member objects will then result
in one large repetition of copies from and to the same memory locations.
To avoid this behaviour I would strongly recommend to implement your
own copy constructor or assignment whenever you use a union, because a
memberwise copy is usually not desired.

Let's combine this with the problems of a) and b):

class GenericInterpreter {
    union opcode {
        opcode(const opcode&);               // replace implicitly defined
        opcode& operator = (const opcode&);  // memberwise copy versions

        short tag;
        struct { short tag; short data; } op1;
        struct { short tag; char* data; } op2;
    };
};

class SpecialInterpreter : public GenericInterpreter {
    union opcode {
        GenericInterpreter::opcode      generic; // error: non-trivial member
        short tag;
        struct { short tag; long  data; } op3;
        struct { short tag; float data; } op4;
    };
};

class ValidInterpreter : public GenericInterpreter {
    union opcode {
        // using copy - paste instead of language features
        short tag;
        struct { short tag; short data; } op1;
        struct { short tag; char* data; } op2;
        //
        struct { short tag; long  data; } op3;
        struct { short tag; float data; } op4;
    };
};

In my opinion, comparing the copy constructor/assignments to others, they
are only special regarding their use by the implicitly defined memberwise
copy constructor/assignment by outside classes. Here I can't find a reason
why a member's custom copy methods should not be applicable instead.

Conclusion, just dreaming:
 I would generally prefer " ... constructors and destructor of member
 objects are ignored, if not explicitly called by the union's ctor/dtor.
 The union's implicit default copy constructor / assignment does a
 binary copy instead of memberwise copy. Objects <containing a vptr>
 cannot be member of a union" - Please pardon my shortcut on vptrs.

d) anonymous union

Why is there no anonymous struct? This is not only for symmetric reasons,
but anonymous structs inside unions may be as useful as anonymous unions
inside structs.


Best regards
Dirk

------------------------------------------------------------------
Dirk Becker                                dirk@becker.adviser.com
Harderweg 76, 22549 Hamburg, Germany          Tel. +49 40 80783143
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Technical Details
Message-ID: <v01530500ad38ee830c96@[194.163.74.11]>
Path: arc1-ca.pugleaf.net!in1.uu.net!bounce-back

Show Full Headers
Complete Article Headers
From: dirk@becker.adviser.com (Dirk Becker)
Message-ID: <v01530500ad38ee830c96@[194.163.74.11]>
X-Original-Date: Sat, 3 Feb 1996 17:51:10 +0100
Path: arc1-ca.pugleaf.net!in1.uu.net!bounce-back
Date: 03 Feb 96 17:22:11 GMT
Approved: fjh@cs.mu.oz.au
Organization: -
Newsgroups: comp.std.c++
X-Sender: dirk@194.163.74.12
Content-Type: text/plain; charset="us-ascii"
Subject: class.union questions
X-Auth: PGPMoose V1.1 PGP comp.std.c++
 iQBFAgUBMROZ5uEDnX0m9pzZAQEB1AF/WVxISufM6sQ04fYfOhDI3Fb7rSvzecsv
 +QUvYRtGliDB8QMAlJXz6Noo1sFrdVnl
 =O7qD