C++ Union, Struct, Member type
Asked Answered
M

6

6

If I have a class:

class Odp
{
    int i;
    int b;
    union
    {
         long f;
         struct
         {
               WCHAR* pwszFoo;
               HRESULT hr;
         };
    };

}

Union means that, of all values listed, it can only take on one of those values at a time? How does that work in terms of accessing these variables? How would I access hr directly? If I set hr, what happens if I try to access f?

Manful answered 18/6, 2010 at 17:23 Comment(0)
P
11

This is a very fraught area in the C++ standard - basically a union instance, per the standard can only be treated at any one time as if it contained one "active" member - the last one written to it. So:

union U {
   int a;
   char c;
};

then:

U u;
u.a = 1;
int n = u.a;
u.c = 2;
char c = u.c;

is OK, but:

U u;
u.a = 1;
char c = u.c;

is not. However, there are vast volumes of existing code that say that both are OK. and in neither, or any, case will an exception be thrown for an "invalid" access. The C++ language uses exceptions exceptionally (!) sparingly.

Basically, if you find yourself using unions in your C++ code to deal with anything but C libraries, something is wrong.

Photogrammetry answered 18/6, 2010 at 17:39 Comment(1)
+1 -- but even for C libraries reinterpret_cast is usable instead of a union most of the time.Kale
C
5

Every time you set (write to) a member of a union, you essentially make it "active". You are only allowed to read the currently active member of the union. It means that it is your responsibility to remember somehow which member is active at each moment in time.

Attempting to access the inactive member of a union leads to undefined behavior.

Keep in mind also that your code is not valid C++. There's no such thing as "anonymous struct" in C++. Your struct member has to have a name. If your compiler accepts it, it is just a non-standard extension supported by your specific compiler.

Catfall answered 18/6, 2010 at 17:28 Comment(3)
Hmm... I knew the result would be to return undefined data, but AFAIK the act of accessing the other member shouldn't cause undefined behavior like accessing the target of a null pointer does.Kale
@Billy ONeal: Yes, it should, for obvious reasons. Since the types are generally unrelated, the other (inactive) member can easily end up with trap representation. Which is the main (and obvious) reason the behavior is undefined.Catfall
"trap representation" <-- Never heard of that one before. +1Kale
R
2

Right, with a union the same memory locations will be used to represent a single one of the members at any given time. So if you have an instance of the union and set the value of hr, you will get garbage if you then try to read the value of f.

Try using the following to access hr:

union a;
a.hr = NULL;
Rosinweed answered 18/6, 2010 at 17:26 Comment(3)
So it's up to the programmer to guard against it, or will an exception be thrown?Manful
@Rosarch: This is a C feature; C does not have exceptions. Use unions at your own risk :)Kale
No exception will be thrown; it is up to the programmer to make sure they are accessing the proper member of the union.Rosinweed
D
1

It just means you can access the same memory as either the long, or the struct.

To access hr:

Odp o1;
o1.hr;

Interesting link: http://www.cplusplus.com/forum/general/18816/

Denbighshire answered 18/6, 2010 at 17:24 Comment(7)
In this case, the struct doesn't have a name. How would I access it?Manful
@Rosarch: Technically it's illegal in C. It's legal in C++, in which case the names are exposed as members of class Odp.Kale
@Billy ONeal: Incorrect. "Anonymous structs" are illegal in C++. C++ supports anonymous unions, but not anonymous structs. The OP's declaration is ill-formed.Catfall
@John Weldon: The link in your answer doesn't suggest anything, until you get to "jsmith's" post, which correctly states that the code is illegal.Catfall
I concede, given that I don't know the answer definitively :)Denbighshire
@John Weldon: In your answer, Odp o1(); declares a function, not an object. Somehow It think this wasn't your intent.Catfall
@AndreyT; do you want to review any of my other answers? You're on a streak :DDenbighshire
R
0

Attempt to access "f" will give you some result. It will likely be representation other member of union as data type of "f", i.e. in this case you are likely will be reading partial or entire content of the "pwszFoo" represented as "long" data type. General concept is easy - union members share the same location in memory.

Remiss answered 15/9, 2016 at 9:25 Comment(0)
P
0

The Union will allocate enough memory for the largest type (thing) in the union. So you may have many types of objects that have large memory foot prints and you will only be passing one of them at a time to some other place in your code. The Union lets you do that. It's one step up from passing a void pointer. In either case you need to devise a way to known what is stored in an instance of a Union. The code below is a simple way to do that by wrapping the Union in a structure. The structure defines an enumeration to identify the item used by the Union and provides a place to store the enumerated type.

    union UnionItem {
      int a;
      float b;
      double c;
   };

   struct UnionObj {
      enum Type{
         I, F, D
      };
      Type t;
      UnionItem item;
   };

   UnionObj o;
   o.item.b = 2.3f;
   o.t = UnionObj::F;

   // Usually the UnionObj would be passed to other functions or methods.

   switch (o.t) {
   case UnionObj::I:
      cout << o.item.a;
      break;
   case UnionObj::F:
      cout << o.item.b;
      break;
   case UnionObj::D:
      cout << o.item.c;
      break;
   default:
      cout << "Something wrong!";
   }
Pasture answered 22/11, 2022 at 21:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.