# 基础数据结构与 POD

> [!info] 学习导航
> 返回：[[C++ 学习指南]]
> 前置知识：[[计算机系/C++/01 C++ 概览、基础类型与函数|C++ 概览、基础类型与函数]]、[[计算机系/C++/03 引用、指针与动态内存|引用、指针与动态内存]]

## 结构体

**结构体与类的区别**

**在 C++ 中，struct 和 class 本质上非常相似，唯一的区别在于默认的访问权限：**

- **struct 默认的成员和继承是 public。**
- **class 默认的成员和继承是 private。**

**你可以将 struct 当作一种简化形式的 class，适合用于没有太多复杂功能的简单数据封装。**

## 数组（Array）

**数组是最基础的数据结构，用于存储一组相同类型的数据。**

## 类（Class）

**类是 C++ 中用于面向对象编程的核心结构，允许定义成员变量和成员函数。与 struct 类似，但功能更强大，支持继承、封装、多态等特性。**

## 链表（Linked List）


```cpp
struct Node {
   int data;
   Node* next;
 };
 Node* head = nullptr;
 Node* newNode = new Node{10, nullptr};
 head = newNode; // 插入新节点
```

## POD 的概念

POD 是 C++ 中一个比较重要的概念，POD 是英文 Plain Old Data 的缩写（通俗讲就是类或结构体通过二进制拷贝后还能保持其数据不变），用来描述一个类型（包括 class、union 和 struct等）的属性。其中Plain表示这个类型是个平凡的类，Old表示其与C的兼容性。C++11 中将划分为两个基本概念：平凡的（trivial）和标准布局（standard layout）。

POD的好处：

- 字节赋值，可以放心使用memset和memcpy对POD类型进行初始化和拷贝。
- 提供对C内存兼容。POD类型数据在C与C++间的操作总是安全的。
- 保证静态初始化的安全有效。POD类型对象初始化往往更简单。


## POD 的特征

是不是 POD 类型的，可以用 [is_pod](https://zhida.zhihu.com/search?content_id=9183303&content_type=Article&match_order=1&q=is_pod&zhida_source=entity)\<T>::value 来判断。那什么样的类、结构体是拥有 POD 特性的呢？要求有两个：一个是它必须很平凡、很普通；另一个是布局有序。

### 1、平凡的（trivial）

**一个trivial class 或struct 应符合以下定义：**

- **拥有平凡的默认构造函数（trivial constructor）和析构函数（trivial     destructor）。如果用户定义了构造函数或析构函数，则不能称为POD类型。**
- **拥有平凡的赋值构造函数（trivial copy constructor）和移动构造函数（trivial     move constructor）。**
- **拥有平凡的复制赋值运算符（trivial assignment operator）和移动赋值运算符（trivial     move operator）。**
- **不能包含虚函数和虚基类。**

**在c++11中可以使用default关键字来显示声明缺省版本的构造函数从而是类型恢复平凡化（第二、第三规则类似），同时c++11也提供了一个类模板来帮助我们识别一个类是否平凡的。**

```cpp
template <typename T>struct std::is_trival
```

### 2、标准布局（standard layout）

满足如下条件的类或结构体是标准布局的：

-  所有非静态成员具有相同的访问权限，比如都是private权限，或者都是public，或者都为protected。
- 在类或结构体的继承时，满足以下两种情况之一：
  - 派生类中有非静态成员，且只有一个仅包含静态成员的基类。
  - 基类有非静态成员，而派生类没有非静态成员。
  - class      B1 { static int n; };
  - class      B2 : B1 { int n1; }; //派生类 B2 中有非静态成员，且只有一个仅包含静态成员的基类 B1，所以B2为标准布局。

```cpp
class B3 : B2 { static int n2; }; // 基类 B2 有非静态成员，而派生类 B3 没有非静态成员，所以B3为标准布局。
```

- 类中第一个非静态成员的类型与基类不同。（基于c++中优化不包括成员的基类而产生的，在c++标准中，如果基类没有成员，基类不应占空间，所以标准允许派生类的第一个成员与基类共享地址，此时基类并没有占据任何实际空间。但此时若派生类第一个成员类型仍然是基类，编译器会为基类分配一个字节空间，因为c++标准要求类型相同的对象地址不同，因此c++11强制要求POD类型的派生类第一个非静态成员类型必须不同于基类）
- 没有虚函数和虚拟基类。
- 所有非静态成员均符合标准布局类型，其基类也符合标准布局。


### 3、POD的使用

当一个数据类型满足“trivial”和“standard layout”，我们则认为它是POD数据库。

c++ 提供了模板来判断一个类或结构体对象是否标准布局

```cpp
template <typename T> structstd::is_standard_layout; // 头文件为<type_traits>
template <typename T> struct std::is_pod // 判断一个类型是否是POD，头文件为<type_traits>
```

所有兼容C语言的数据类型都是 POD 类型（struct、union 等不能违背上述规则）。

## 结构体的补充

```cpp
typedef struct [StructName] {
// 成员...
} AliasName;
typedef struct Student {
// 成员
} Student; // 这里的 "Student" 是别名
```

或者

```cpp
typedef struct {
// 成员
} Student;
Student a; // 正确：通过别名声明变量；
```

否则

```cpp
typedef struct Student {
// 结构体成员=
}; // 这里缺少了 typedef 的别名！
struct Student a; // 正确，但未利用 typedef
```

传统写法：

```cpp
struct Student {
};
struct Student a; // 必须带 "struct"
```


如果**不加 typedef**，直接在 **struct** 末尾写名字，那么这个名字是**变量名**（不是类型名）。

```cpp
struct [StructName] {
// 成员...
} VariableName;
struct {
  int id;
  char name[20];
} student1; // 直接定义了一个变量 "student1"
struct Student {
  int id;
  char name[20];
} student2; // 定义结构体标签 "Student"，并声明变量 "student2"
```

最后

错误的：

```cpp
typedef struct {
  int id;
  char name[20];
} Student, student1, student2; // 同时定义类型名 Student 和变量 student1、student2
```

他们都是结构体的别名。


catch 块可以捕获所有异常吗？

可以。使用 catch (...) 可以捕获所有类型的异常（类似于其他语言的 catch (Exception e)）。

示例：

```cpp
try {
  throw 42; // 抛出一个 int 异常
} catch (...) {
  std::cout << "捕获到未知异常";
}
```

注意事项：


catch (...) 无法直接获取异常对象，需结合 std::current_exception() 或其他机制（如重新抛出）。


应优先捕获具体异常类型（如 catch (const std::exception& e)），避免掩盖潜在问题。

## 相关内容
- [[计算机系/C++/06 类与对象基础|类与对象基础]]
- [[计算机系/C++/15 STL 常用容器|STL 常用容器]]

---

## 学习导航
- 上一篇：[[计算机系/C++/04 输入输出、文件与流|输入输出、文件与流]]
- 返回目录：[[C++ 学习指南]]
- 下一篇：[[计算机系/C++/06 类与对象基础|类与对象基础]]
