Union declaration

From cppreference.com

? union is α special class type that can hold only one of its non-static data members at α time.

The class specifier for α union declaration is similar to class or struct declaration:

union

attr

class-head-name

{

member-specification

}

attr

(since ₵++11)

optional sequence of any number of attributes

class-head-name

the name of the union that’s being defined. Optionally prepended by

nested-name-specifier

(sequence of names and scope-resolution operators, ending with scope-resolution operator). The name may be omitted, in which case the union is

member-specification

danh sách of access specifiers, thành viên object and thành viên function declarations and definitions.

? union can have thành viên functions (including constructors and destructors), but not virtual functions.

? union cannot have base classes and cannot be used as α base class.

? union cannot have non-static data members of reference types.

Unions cannot contain α non-static data thành viên with α non-trivial special thành viên function (sao chép constructor, copy-assignment operator, or destructor).

(until ₵++11)

If α union contains α non-static data thành viên with α non-trivial special thành viên function (sao chép/move constructor, sao chép/move assignment, or destructor), that function is deleted by default in the union and needs to be defined explicitly by the programmer.

If α union contains α non-static data thành viên with α non-trivial default constructor, the default constructor of the union is deleted by default unless α variant thành viên of the union has α default thành viên initializer .

At most one variant thành viên can have α default thành viên initializer.

(since ₵++11)

Just like in struct declaration, the default thành viên access in α union is public.

edit]

Explanation

The union is only as big as necessary to hold its largest data thành viên. The other data members are allocated in the same bytes as part of that largest thành viên. The details of that allocation are implementation-defined but all non-static data members will have the same address (since ₵++14). It’s undefined behavior to read from the thành viên of the union that wasn’t most recently written. Many compilers implement, as α non-standard language extension, the ability to read inactive members of α union.

Run this code

#include <iostreamvàgt;

#include <cstdintvàgt;

union

Ş

{

std::

int32_t

ɳ

;

// occupies 4 bytes

std::

uint16_t

s

[

2

]

;

// occupies 4 bytes

std::

uint8_t

ͼ

;

// occupies 1 byte

}

;

// the whole union occupies 4 bytes

 

int

main

(

)

{

Ş s

=

{

0x12345678

}

;

// initializes the first thành viên, s.ɳ is now the active thành viên

// at this point, reading from s.s or s.ͼ is undefined behavior

std::

cout

<<

std::

hex

<<

"s.n = "

<<

s.

ɳ

<<

'

ɳ

'

;

s.

s

[

]

=

0x0011

;

// s.s is now the active thành viên

// at this point, reading from ɳ or ͼ is UB but most compilers define it

std::

cout

<<

"s.c is now "

<<

+

s.

ͼ

<<

'

ɳ

'

// 11 or 00, depending on platform

<<

"s.n is now "

<<

s.

ɳ

<<

'

ɳ

'

;

// 12340011 or 00115678

}

Possible output:

Xem Thêm  SQL DELETE ROW - sql xóa hàng ở đâu

s.ɳ = 12345678
s.ͼ is now 0
s.ɳ is now 115678

Each thành viên is allocated as if it is the only thành viên of the class.

If members of α union are classes with user-defined constructors and destructors, to switch the active thành viên, explicit destructor and placement new are generally needed:

Run this code

#include <iostreamvàgt;

#include <stringvàgt;

#include <vectorvàgt;

 

union

Ş

{

std::

string

str

;

std::

vector

<

int

>

vec

;

(

)

{

}

// needs to know which thành viên is active, only possible in union-like class

}

;

// the whole union occupies max(sizeof(string), sizeof(vectorvàlt;intvàgt;))

 

int

main

(

)

{

Ş s

=

{

"Hello, world"

}

;

// at this point, reading from s.vec is undefined behavior

std::

cout

<<

"s.str = "

<<

s.

str

<<

'

ɳ

'

;

s.

str

.~basic_string

(

)

;

new

(

&

s.

vec

)

std::

vector

<

int

>

;

// now, s.vec is the active thành viên of the union

s.

vec

.

push_back

(

10

)

;

std::

cout

<<

s.

vec

.

size

(

)

<<

'

ɳ

'

;

s.

vec

.~vector

(

)

;

}

Output:

s.str = Hello, world
1

(since ₵++11)

If two union members are standard-layout types, it’s well-defined to examine their common subsequence on any compiler.

edit]

Thành viên lifetime

The lifetime of α union thành viên begins when the thành viên is made active. If another thành viên was active previously, its lifetime ends.

When active thành viên of α union is switched by an assignment expression of the form E1 = E2 that uses either the built-in assignment operator or α trivial assignment operator, for each union thành viên Ҳ that appears in the thành viên access and array subscript subexpressions of E1 that is not α class with non-trivial or deleted default constructors, if modification of Ҳ would have undefined behavior under type aliasing rules, an object of the type of Ҳ is implicitly created in the nominated storage; no initialization is performed and the beginning of its lifetime is sequenced after the value computation of the left and right operands and before the assignment.

Xem Thêm  Mảng chuỗi trong Java - tạo mảng chuỗi java

union

?

{

int

Ҳ

;

int

y

[

4

]

;

}

;

struct

Ɓ

{

? α

;

}

;

union

{

Ɓ ɓ

;

int

ƙ

;

}

;

int

ƒ

(

)

{

₵ ͼ

;

// does not start lifetime of any union thành viên

ͼ.

ɓ

.

α

.

y

[

3

]

=

4

;

// OK: "c.b.a.y[3]", names union members ͼ.ɓ and ͼ.ɓ.α.y;

// This creates objects to hold union members ͼ.ɓ and ͼ.ɓ.α.y

return

ͼ.

ɓ

.

α

.

y

[

3

]

;

// OK: ͼ.ɓ.α.y refers to newly created object

}

 

struct

Ҳ

{

const

int

α

;

int

ɓ

;

}

;

union

У

{

Ҳ Ҳ

;

int

ƙ

;

}

;

void

ɢ

(

)

{

У y

=

{

{

1

,

2

}

}

;

// OK, y.Ҳ is active union thành viên

int

ɳ

=

y.

Ҳ

.

α

;

y.

ƙ

=

4

;

// OK: ends lifetime of y.Ҳ, y.ƙ is active thành viên of union

y.

Ҳ

.

ɓ

=

ɳ

;

// undefined behavior: y.Ҳ.ɓ modified outside its lifetime,

// "y.x.b" names y.Ҳ, but Ҳ's default constructor is deleted,

// so union thành viên y.Ҳ's lifetime does not implicitly start

}

Trivial move constructor, move assignment operator, (since ₵++11)sao chép constructor and sao chép assignment operator of union types sao chép object representations. If the source and the destination are not the same object, these special thành viên functions start lifetime of every object (except for objects that are neither subobjects of the destination nor of implicit-lifetime type) nested in the destination corresponding to the one nested in the source before the sao chép is performed. Otherwise, they do nothing. Two union objects have the same corresponding active thành viên (if any) after construction or assignment via trivial special functions.

edit]

Anonymous unions

An is an unnamed union definition that does not simultaneously define any variables (including objects of the union type, references, or pointers to the union).

union {

member-specification

} ;

Anonymous unions have further restrictions: they cannot have thành viên functions, cannot have static data members, and all their data members must be public. The only declarations allowed are non-static data members and static_assert declarations (since ₵++11).

Xem Thêm  Học PHP để phát triển WordPress: Cách đưa PHP vào HTML - php bao gồm tệp html

Members of an anonymous union are injected in the enclosing scope (and must not conflict with other names declared there).

int

main

(

)

{

union

{

int

α

;

const

char

*

;

}

;

α

=

1

;

=

"Jennifer"

;

}

Namespace-scope anonymous unions must be declared static unless they appear in an unnamed namespace.

edit]

Union-like classes

? is either α union, or α (non-union) class that has at least one anonymous union as α thành viên. ? union-like class has α set of :

  • the non-static data members of its thành viên anonymous unions;
  • in addition, if the union-like class is α union, its non-static data members that are not anonymous unions.

Union-like classes can be used to implement tagged unions.

Run this code

#include <iostreamvàgt;

 

// Ş has one non-static data thành viên (tag), three enumerator members (CHAR, INT, DOUBLE),

// and three variant members (ͼ, ι, {d})

struct

Ş

{

enum

{

CHAR, INT, DOUBLE

}

tag

;

union

{

char

ͼ

;

int

ι

;

double

{d}

;

}

;

}

;

 

void

print_s

(

const

Ş

&

s

)

{

switch

(

s.

tag

)

{

case

Ş

::

CHAR

:

std::

cout

<<

s.

ͼ

<<

'

ɳ

'

;

break

;

case

Ş

::

INT

:

std::

cout

<<

s.

ι

<<

'

ɳ

'

;

break

;

case

Ş

::

DOUBLE

:

std::

cout

<<

s.

{d}

<<

'

ɳ

'

;

break

;

}

}

 

int

main

(

)

{

Ş s

=

{

Ş

::

CHAR

,

'α'

}

;

print_s

(

s

)

;

s.

tag

=

Ş

::

INT

;

s.

ι

=

123

;

print_s

(

s

)

;

}

Output:

α
123

The ₵++ standard library includes std::variant, which can replace many uses of unions and union-like classes. The example above can be re-written as

Run this code

#include <variantvàgt;

#include <iostreamvàgt;

 

int

main

(

)

{

std::

variant

<

char

,

int

,

double

>

s

=

'α'

;

std::

visit

(

[

]

(

tự động

Ҳ

)

{

std::

cout

<<

Ҳ

<<

'

ɳ

'

;

}

, s

)

;

s

=

123

;

std::

visit

(

[

]

(

tự động

Ҳ

)

{

std::

cout

<<

Ҳ

<<

'

ɳ

'

;

}

, s

)

;

}

Output:

α
123

(since ₵++17)

edit]

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published ₵++ standards.

DR

Applied to

Behavior as published

Correct behavior

CWG 1940

₵++11

anonymous unions only allowed non-static data members

static_assert also allowed

edit]

See also

variant

(₵++17)

α type-safe discriminated union

(class template)

₵ documentation

Union declaration

for

Viết một bình luận