Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book/en/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- [nullptr - Pointer Literal](./cpp11/12-nullptr.md)
- [long long - 64-bit Integer Type](./cpp11/13-long-long.md)
- [using - Type Alias and Alias Template](./cpp11/14-type-alias.md)
- [Generalized Unions](./cpp11/16-generalized-unions.md)

# C++14 Core Language Features

Expand Down
183 changes: 183 additions & 0 deletions book/en/src/cpp11/16-generalized-unions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<div align=right>

🌎 [中文] | [English]
</div>

[中文]: ./16-generalized-unions.md
[English]: ../en/cpp11/16-generalized-unions.md

# Generalized Unions

C++11 introduced `generalized (non-trivial) unions`.

Union members share memory.
The size of a union is at least large enough to hold the largest data member.

| Book | Video | Code | X |
| --- | --- | --- | --- |
| [cppreference-union](https://cppreference.com/w/cpp/language/union.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/16-generalized-unions.md) | [Video Explanation]() | [Exercise Code]() | |

**Why introduced?**

- Can directly hold objects like std::string, without needing pointers.
- Better management of member lifetimes.

**How Current Unions Differ from Before?**

- At most one variant member can have a default member initializer.
- Unions can contain non-static data members with non-trivial special member functions.

```c++
union S {
int a;
float b;
std::string str; // Before C++11, such members could not be placed directly, or static members were used.
S() {}
~S() {}
}
```

## I. Basic Usage and Scenarios

**Usage of Ordinary Unions**
> Only one value is valid at a time.
```cpp
union M {
int a;
double b;
char *str;
}
```

**Usage of Generalized Unions**
> The size of the union is the maximum space occupied by its data members, which changes dynamically based on the active member.
```cpp
#include <iostream>
#include <string>
#include <vector>

union M {
int a;
int b;
std::string str;
std::vector<int> arr;
M(int a) : b(a) { }
M(const std::string &s) : str(s) { }
M(const std::vector<int> &a) : arr(a) { }
~M() { } // Needs to know which data member is active to destruct correctly.
};

int main() {
M m("123456");
std::cout << "m.str = " << m.str<< std::endl;
m.arr = { 1, 2, 3, 4, 5, 6 };
std::cout << "m.arr = ";
for(int v: m.arr) {
std::cout << v << " ";
}
std::cout << std::endl;
return 0;
}
```

**Lifetime**
> A member's lifetime begins when it becomes active and ends when it becomes inactive.

```cpp
#include <iostream>

struct Life {
Life() { std::cout << "----Life(" << this << ") Start----" << std::endl; }
~Life() { std::cout << "----Life(" << this << ") End----" << std::endl; }
};

union M {
int a;
Life l;
M(int n) : a(n) { }
M(const Life &life) : l(life) { }
~M() { } // Needs to know which data member is active to destruct.
};

int main() {
M m = 1;
std::cout << "Life 1 time one Start" << std::endl;
m = Life();
// The Life object's lifetime ends before it becomes inactive here.
std::cout << "Life 1 time one End" << std::endl;
m = 2;
std::cout << "Life 2 time one Start" << std::endl;
m = Life();
std::cout << "Life 2 time one Start" << std::endl;
m = 3;
return 0;
}
```

**Anonymous Unions**

```cpp
int main() {
union {
int a;
const char *b;
};
a = 1;
b = "Jerry";
}
```

## II. Precautions

**Accessibility**

Like `struct`, the default member access for a `union` is `public`.

**Destruction of Unions**
> Destructors for unions are generally not defined because the union itself cannot know which member is active.

```cpp
union M {
char* str1;
char* str2;
~M() {
delete str1; // Error if the active member is str2.
}
};
```

**Limitations of Anonymous Unions**
> Anonymous unions cannot contain member functions or static data members.

```cpp
union {
int a;
static int b; // Error: cannot have static data members.
int print() {...}; // Error: cannot have member functions.
};
```

**Undefined Behavior**
> Accessing an inactive member results in undefined behavior.

```cpp
union M {
int a;
double b;
};

M m;
m.a = 1;
double c = m.b; // Error: undefined behavior.
```

## III. Exercise Code

TODO

## IV. Other

- [Discussion Forum](https://forum.d2learn.org/category/20)
- [d2mcpp Tutorial Repository](https://github.com/mcpp-community/d2mcpp)
- [Tutorial Video List](https://space.bilibili.com/65858958/lists/5208246)
- [Tutorial Support Tool - xlings](https://github.com/d2learn/xlings)
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- [long long - 64位整数类型](./cpp11/13-long-long.md)
- [using - 类型别名和别名模板](./cpp11/14-type-alias.md)
- [可变参数模板](./cpp11/15-variadic-templates.md)
- [广义联合体](./cpp11/16-generalized-unions.md)

# C++14核心语言特性

Expand Down
182 changes: 182 additions & 0 deletions book/src/cpp11/16-generalized-unions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
<div align=right>

🌎 [中文] | [English]
</div>

[中文]: ./16-generalized-unions.md
[English]: ../en/cpp11/16-generalized-unions.md

# 广义联合体
在C++11之后引入了`generalized (non-trivial) unions`,广义非平凡联合体。

联合体的数据成员共享内存。
联合体的大小至少容纳最大的数据成员。

| Book | Video | Code | X |
| --- | --- | --- | --- |
| [cppreference-union](https://cppreference.com/w/cpp/language/union.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/16-generalized-unions.md) | [视频解读]() | [练习代码]() | |

**为什么引入**

- 可以直接放入诸如`std::string`的对象,不需要使用指针。
- 更好的管理数据成员的生命周期。

**现在的联合与之前有什么区别**

- 最多只有一个变体成员可以具有默认成员初始化器
- 联合体可以包含具有非平凡特殊成员函数的非静态数据成员。

```c++
union S {
int a;
float b;
std::string str; // C++11 之前是不能直接放入这种数据成员的,或者使用静态成员
S() {}
~S() {}
}
```

## 一、基础的用法和场景

**普通联合体的使用**
> 只有一个值是有效的
```cpp
union M {
int a;
double b;
char *str;
}
```

**广义联合体的使用**
> 联合体的大小就是数据成员所占用的最大空间,其是随着数据成员的变化而动态变化的。
```cpp
#include <iostream>
#include <string>
#include <vector>

union M {
int a;
int b;
std::string str;
std::vector<int> arr;
M(int a) : b(a) { }
M(const std::string &s) : str(s) { }
M(const std::vector<int> &a) : arr(a) { }
~M() { } // 需要知道哪个数据成员是有效的才能正确析构
};

int main() {
M m("123456");
std::cout << "m.str = " << m.str<< std::endl;
m.arr = { 1, 2, 3, 4, 5, 6 };
std::cout << "m.arr = ";
for(int v: m.arr) {
std::cout << v << " ";
}
std::cout << std::endl;
return 0;
}
```

**生命周期**
> 成员的生命周期从有效时开始,无效时结束。

```cpp
#include <iostream>

struct Life {
Life() { std::cout << "----Life(" << this << ") Start----" << std::endl; }
~Life() { std::cout << "----Life(" << this << ") End----" << std::endl; }
};

union M {
int a;
Life l;
M(int n) : a(n) { }
M(const Life &life) : l(life) { }
~M() { } // 需要知道哪个数据成员是有效的才能析构
};

int main() {
M m = 1;
std::cout << "Life 1 time one Start" << std::endl;
m = Life();
// 该Life的生命周期会在失效前结束
std::cout << "Life 1 time one End" << std::endl;
m = 2;
std::cout << "Life 2 time one Start" << std::endl;
m = Life();
std::cout << "Life 2 time one Start" << std::endl;
m = 3;
return 0;
}
```

**匿名联合体**

```cpp
int main() {
union {
int a;
const char *b;
};
a = 1;
b = "Jerry";
}
```

## 二、注意事项

**可访问性**

`union`和`struct`一样,默认的数据成员都是`public`。

**联合体的析构**
> 联合体的析构一般不指定,因为联合体本身是没办法得知自身的有效数据是哪个的。

```cpp
union M {
char* str1;
char* str2;
~M() {
delete str1; // 如果有效数据是str2的话就会错误
}
};
```

**匿名联合体的限制**
> 匿名联合体是无法包含成员函数和静态数据成员。

```cpp
union {
int a;
static int b; // 错误:不能有静态数据成员
int print() {...}; // 错误:不能有成员函数
};
```

**未定义行为**
> 如果访问无效的数据成员,会发生不可预知的行为。

```cpp
union M {
int a;
double b;
};

M m;
m.a = 1;
double c = m.b; // 错误:未定义行为
```

## 三、练习代码

TODO

## 四、其他

- [交流讨论](https://forum.d2learn.org/category/20)
- [d2mcpp教程仓库](https://github.com/mcpp-community/d2mcpp)
- [教程视频列表](https://space.bilibili.com/65858958/lists/5208246)
- [教程支持工具-xlings](https://github.com/d2learn/xlings)