Examples of C ++ consortium union usage
This example describes how to use the C ++ consortium union. Share it with you for your reference. The details are as follows:
We should use union according to convention in C. This is my point of view in this article. Although C ++ allows us to expand some new things, I suggest you do not do that. After reading this article, I think you probably think so too.
C. Because there is no concept of class, all types can be considered as a combination of basic types, it is natural to include struct in union, after C ++, since it is generally believed that struct in C ++ is basically equivalent to class, can there be class members in union? Let's take a look at the following code:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Struct TestUnion { TestUnion (){} }; Typedef union { TestUnion obj; } UT; Int main (void) { Return 0; } |
Compile the program and we will be notified:
Error C2620: union '_ unnamed': member 'obj 'has user-defined constructor or non-trivial default constructor
If the constructor with nothing to do is removed, everything is OK.
Why does the compiler not allow our union members to have Constructors? I cannot find an authoritative explanation of this issue. For this question, my explanation is:
If the C ++ standard allows our union to have constructors, do we need to execute this constructor during space allocation? If the answer is yes, if the TestUnion constructor contains some memory allocation operations or other modifications to the entire application state, if I want to use obj in the future, it may be reasonable, but what if I don't use the obj member at all? The modification to the system status caused by the introduction of obj is obviously unreasonable; otherwise, if the answer is no, once we select obj for future operations, all information is not initialized (if it is a normal struct, there is no problem, but what if there is a virtual function ?). Furthermore, let's assume that our union is not only one TestUnion obj, but also one TestUnion2 obj2. Both of them have constructors, in addition, some memory allocation tasks are executed in the constructor (many other tasks are done). If obj is constructed first, and obj2 is constructed later, then the execution result will almost certainly cause memory leakage.
In view of the above troubles (there may be more trouble), when constructing a union, the compiler is only responsible for allocating space and not executing additional initialization tasks. In order to simplify the work, as long as the constructor is provided, the above error will be received.
Likewise, except constructors, destructor, copy constructors, and value assignment operators cannot be added.
In addition, if our class contains any virtual functions, we will receive the following error message during compilation:
Error C2621: union '_ unnamed': member 'obj 'has copy constructor
Therefore, the idea that union contains class member variables with Constructors/destructor/copy constructors/assign value operators/virtual functions is dispelled, be honest with your C-style struct!
However, defining a common member function is OK, because it does not make any essential difference between the class and the C-style struct, you can fully understand this class as a C-style struct + n global functions.
Now let's look at the differences when the class contains internal union. Take a look at the following procedures and read the program prompts:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
Class TestUnion { Union DataUnion { DataUnion (const char *); DataUnion (long ); Const char * ch _; Long l _; } Data _; Public: TestUnion (const char * ch ); TestUnion (long l ); }; TestUnion: TestUnion (const char * ch): data _ (ch) // if you want to use initialing list to initiate a nested-union member, the union must not be anonymous and must have a constructor. {} TestUnion: TestUnion (long l): data _ (l) {} TestUnion: DataUnion (const char * ch): ch _ (ch) {} TestUnion: DataUnion (long l): l _ (l) {} Int main (void) { Return 0; } |
As shown in the above program, union in C ++ can also contain constructors. However, although this is supported by languages, it is really a bad programming habit. Therefore, I don't want to explain too much about the above program. I recommend the following programming style:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
Class TestUnion { Union DataUnion { Const char * ch _; Long l _; } Data _; Public: TestUnion (const char * ch ); TestUnion (long l ); }; TestUnion: TestUnion (const char * ch) { Data _. ch _ = ch; } TestUnion: TestUnion (long l) { Data _. l _ = l; } Int main (void) { Return 0; } |
It is completely C-style.
So accept this conclusion:
Use union according to convention in C. Try not to use any additional C ++ features.
Union is a good thing, and union is a struct. All members in the union share a piece of memory, which is determined by the size of the largest member. when accessing members, the memory is parsed as a member; in gamedev, union can make a difference in these aspects:
1. Name Change:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Struct Rename { Public: Union { Struct { Float x, y, z, w; }; Struct { Float vec [4]; }; }; }; |
In this way, we can access the variable according to the specific meaning, or the loop like an array;
2. Compression:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Struct Compression { Public: Bool operator = (const Compression & arg) const {return value = arg. value ;} Union { Struct { Char a, B, c, d, e, f, g; }; Struct { Long value; }; }; }; |
In this way, for centralized processing, such as =, the efficiency will be greatly improved. For example, on a 64-bit machine, it is very convenient to compress and decompress data once or when data is transmitted;
3. Danger:
The anonymous union usage is not standard, so you must confirm on compiler ==> the portability of the compiler is not good;
The size of data on different machine operating systems is different, indicating different, so it is dangerous to use union, especially during transplantation;
However, if the system and compiler are both the same, it is okay to use union in a proper place.
Union is not much seen in C/C ++. However, in some areas where memory requirements are particularly strict, union is frequently used, so what exactly is Union, how to use it, and what should we pay attention? I have tried some simple answers to these questions. There must be some improper answers!
1. What is union?
"Union" is a special class and a data structure of the construction type. Different data types can be defined in a "union". In a variable described as the "union" type, any type of data defined by the Union can be loaded. The data is shared with the same memory segment, which has saved space (there is also a space-saving type: Bit domain ). This is a very special feature and also a feature of union. In addition, like struct, Union default access permissions are also public and also have member functions.
2. What is the difference between Union and structure?
"Union" has some similarities with "structure. But they are essentially different. In the structure, each member has its own memory space. The total length of a structure variable is the sum of the member lengths (except for the empty structure, and the boundary adjustment is not considered ). In "Union", each member shares a piece of memory space. The length of a federated variable is equal to the longest length of each member. It should be noted that the so-called sharing here does not mean that multiple members are loaded into a joint variable at the same time, but that the joint variable can be assigned to any member value, however, only one value can be assigned at a time. If a new value is assigned, the old value is washed away.
The following is an example of how to understand deep integration.
Example 4:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Include <stdio. h> Void main () { Union number {/* Define a Union */ Int I; Struct {/* Define a structure in the Union */ Char first; Char second; } Half; } Num; Num. I = 0x4241;/* Union member assignment */ Printf ("% c \ n", num. half. first, num. half. second ); Num. half. first = 'a';/* assign values to structure members in the Union */ Num. half. second = 'B '; Printf ("% x \ n", num. I ); Getchar (); } |
Output result:
AB
6261
From the above example, we can see that after I is assigned a value, the lower eight bits are the values of first and second. After first and second are assigned a character, the ASCII code of these two characters will also be used as the low-eight-bit and high-eight-bit I.
3. How to define it?
For example:
?
1 2 3 4 5 6 |
Union test { Test (){} Int office; Char teacher [5]; }; |
Defines a union type named test, which contains two members, one is an integer, the member name is office, the other is a character array, and the array name is teacher. After the joint definition, you can describe the joint variables. variables of the test type can be used to store office integer data or teacher character arrays.
4. How to explain it?
The description of Federated variables can be defined first, then explained, and both described and directly described.
Take the test type as an example:
1)
?
1 2 3 4 5 6 |
Union test { Int office; Char teacher [5]; }; Union test a, B;/* indicates that a and B are of the test Type */ |
2)
?
1 2 3 4 5 |
Union test { Int office; Char teacher [5]; } A, B; |
3)
?
1 2 3 4 5 |
Union { Int office; Char teacher [5]; } A, B; |
Variables a and B are of the test type. The length of variable a and variable B should be equal to the longest length of the member test, that is, the length of the teacher array is equal to 5 bytes in total. For example, if the and B variables are given integer values, only four bytes are used. If the character array is given, five bytes are used.
5. How to use it?
Assign values to the federated variables only to the members of the variables. The member of the federated variable is:
Joint variable name. member name
For example, after a is described as a test variable, you can use a. class, a. office
You are not allowed to assign values only to the federated variable name or perform other operations. You are not allowed to assign values to the federated variables during initialization. Values can only be assigned to programs.
It must be emphasized that only one member value can be assigned to a federated variable at a time. In other words, the value of a federated variable is a member value of the federated variable.
6. Anonymous Union
Anonymous union only notifies the compiler that its member variables share an address. The variables themselves are directly referenced and do not use the common dot operator syntax.
For example:
?
1 2 3 4 5 6 7 8 9 10 11 |
# Include <iostream> Void main () { Union { Int test; Char c; }; Test = 5; C = 'a '; Std: cout <I <"" <c; } |
As we can see, the Federated component is referenced as a declared common local variable. In fact, for programs, this is exactly how these variables are used. in addition, although defined in a joint declaration, they have the same scope level as any other local variable in the same program. this means that the name of the member in the anonymous union cannot conflict with any other constant identifier in the same scope.
The following restrictions apply to anonymous union:
Because the vertex operator is not used for anonymous union, the elements contained in the anonymous union must be data, and member functions are not allowed or private or protected members are not allowed. In addition, the global anonymous union must be static. Otherwise, it must be placed in an anonymous namespace.
7. Some points to be discussed:
1) What in the Union cannot be stored?
We know that all the items in the Union share the memory, so static and reference cannot be used, because they cannot share the memory.
2) can classes be put into the Union?
Let's first look at an example:
?
1 2 3 4 5 6 7 8 9 10 11 |
Class Test { Public: Test (): data (0 ){} Private: Int data; }; Typedef union _ test { Test test; } UI; |
But why?
Because consortium cannot store classes with constructors, analysis functions, and copy operators, the compiler cannot guarantee that these objects will not be destroyed because they share the memory, it cannot be guaranteed that the function can be called when it leaves.
3) Is it an anonymous fault ??
Let's take a look at the next piece of code:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Class test { Public: Test (const char * p ); Test (int in ); Const operator char * () const {return Data. ch ;} Operator long () const {return data. l ;} Private: Enum type {Int, String }; Union { Const char * ch; Int I; } Datatype; Type stype; Test (test &); Test & operator = (const test &); }; Test: test (const char * p): stype (String), datatype. ch (p ){} Test: test (int in): stype (Int), datatype. l (I ){ } |
Do you see any problems? Haha, compilation and translation fail. Why? Is there a problem with datatype. ch (p) and datatype. l (I?
Haha, where is the problem? Let's take a look at what happened when constructing the test object. when creating the test object, we naturally need to call its corresponding constructor. In the constructor, of course, we need to call the constructor of its members, so he wants to call the constructor of the datatype member, but he does not call the constructor.
Error.
Note that this is not an anonymous union! Because it is followed by a piece of data!
4) how to effectively prevent access errors?
Union can save memory space, but there is also a certain risk: Get the value of the current object through an inappropriate data member! For example, the above ch and I requests are staggered.
To prevent such errors, we must define an additional object to track the value types currently stored in the union. We call this additional object the 'join' discriminant.
A good experience is to provide a set of access functions for all union data types when processing union objects as class members.
I hope this article will help you with C ++ programming.