19

I saw some code as follows:

class A 
{
private:
    union {
        B *rep;
        A *next;
    }; // no variables of this anonymous defined!

    void func()
    {
        A *p = new A;

        p->next = NULL; // why p has a member variable of 'next'?
    }
};

I have compiled the above code with VS2010 without any error. Here is the question,

why p has member variable 'next'?

    union {
        B *rep;
        A *next;
    };

As far as I know, this is an anonymous union without even defining a variable. How can we access the member variables inside this union like that?

afuzzyllama
  • 6,538
  • 5
  • 47
  • 64
q0987
  • 34,938
  • 69
  • 242
  • 387

4 Answers4

24

Because that's pretty much what an anonymous union does, it defines zero-or-more variables in the enclosing namespace (which in a class declaration makes them field names) which occupy overlapping memory. Hence in use it's the same as if you'd declared

class A 
{
private:
    B *rep;
    A *next;

    void func()
    {
        A *p = new A;

        p->next = NULL;
    }
};

...except for rep and next occupying overlapping space (or given that the two pointers will have the same size, the same space), and hence all the dangers and benefits that come with a named union.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • 'Because that's pretty much what an anonymous union does' -- what a good point is. If I provide a variable in the end of the union definition, then the code will not be correct anymore -- thank you – q0987 Mar 27 '11 at 23:44
15

Here's the quote from the standard that controls this behavior: section [class.union] (wording from C++0x draft n3242)

A union of the form union { member-specification } ; is called an anonymous union; it defines an unnamed object of unnamed type. The member-specification of an anonymous union shall only define non-static data members. [ Note: Nested types and functions cannot be declared within an anonymous union. — end note ] The names of the members of an anonymous union shall be distinct from the names of any other entity in the scope in which the anonymous union is declared. For the purpose of name lookup, after the anonymous union definition, the members of the anonymous union are considered to have been defined in the scope in which the anonymous union is declared.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 2
    @q0987: I think [Jon](http://stackoverflow.com/questions/5453170/usage-of-union-inside-a-class/5453262#5453262) earned the checkmark. I did nothing but quote the standard for reference's sake, to prove that his much more readable answer is correct. I would have used a comment, but I learned long ago that quotes from the standard usually don't FIT in a comment, nor do they format well. – Ben Voigt Mar 28 '11 at 04:17
0

I am not really sure I understand your question.

A has the member p, because you declared it in A inside an anonymous union along with rep.

You did declare a variable! It's just that 'rep' and 'next' share the same memory.

You can access it just the way you did.

anonymous unions (just like structs) put their members in the same namespace as the above namespace is.

It's useful for e.g.:

union W00t {
    struct {
         uint32_t a,b;
    };
    struct {
         uint64_t c;
    };
 }
Ronny Brendel
  • 4,777
  • 5
  • 35
  • 55
  • your answer is not related to my question. I asked "why variable p can access variable next?" – q0987 Mar 27 '11 at 23:34
  • mh I don't get it sorry^^. You DID declare a variable. It's just it does not have a name, thusly using the above namespace? I don't know what to say, really. – Ronny Brendel Mar 27 '11 at 23:37
  • next is really part of A. As is rep. Both are members ... But rep and next share the same 64 bit of memory. ((And p is A*, thus a pointer to an A instance, thus has all the members of A.)) – Ronny Brendel Mar 27 '11 at 23:38
  • 1
    think of unions as structs where every member begins at the same memory location. – Ronny Brendel Mar 27 '11 at 23:40
  • Unions do have a whole lot of rules surrounding their usage that seem to change in every Standard revision (and are considerably different between C and C++). It's hard to pin down exactly when they are usable for menory aliasing. TThey are well-defined for use as a Variant, i.e. when you only read the member that was last-set; after that it gets murky – M.M Jun 24 '14 at 02:33
0

I'm surprised there is a modern compiler which still allows that construct. It is one from the early days of C, circa 1975. In those days, structure and union members were not actually tied to a particular structure, but contained as attributes an offset from a base address and a data type.

The end result was that using a structure or union properly results in correct code with expressions evaluated as expected. The only difference is that misuse of a structure member with a pointer unassociated with the type would not be flagged as an error. I don't think there was any particular reason for not enforcing the associate—K&R hint that future compilers hopefully would check such uses—probably just to save symbol table space in 16-bit land.

wallyk
  • 56,922
  • 16
  • 83
  • 148
  • newest gcc likes it. And imo it makes sense iff you use union { struct { }} ... not having to have another scope/name in between – Ronny Brendel Mar 27 '11 at 23:43
  • 1
    Of course compilers allow that construct, it's part of the standard (and still is, in C++0x). I'll post the relevant section. – Ben Voigt Mar 27 '11 at 23:49
  • It also still has practical use beyond abusing to save space. Plenty of the "bad" things one can do in C and C++ are necessary in some cases when dealing with imposed physical layouts, so while the above would be bad if saving space was the only intent (though even that would be forgiveable on a small device with only a few KB to play with), it can be absolutely vital in some cases. – Jon Hanna Mar 28 '11 at 00:23
  • @BenVoigt anonymous unions were not permitted in C89 or C99. They were added in C11. (They've always been allowed in C++ of course, wally is probably thinking of C) – M.M Jun 24 '14 at 02:30