POD (程序設計)

Plain old data structure, 縮寫為POD, 是C++語言的標準中定義的一類數據結構，POD適用於需要明確的數據底層操作的系統中。POD通常被用在系統的邊界處，即指不同系統之間只能以底層數據的形式進行交互，系統的高層邏輯不能互相兼容。比如當對象的欄位值是從外部數據中構建時，系統還沒有辦法對對象進行語義檢查和解釋，這時就適用POD來存儲數據。

## 定義

POD類型包括下述C++類型，以及其cv-qualified的類型，還有以其為基類型的陣列類型:

- 標量類型(scalar type)
- POD類類型(POD class type)

### 標量類型

術語標量類型包括下述C++類型範疇, 以及其cv-qualified類型:

- 算術類型(arithmetic type)
- 枚舉類型(enumeration type)
- 指針類型(pointer type)
- 指標到成員類型(pointer-to-member type)

術語算術類型包括下述C++類型範疇:

- 整數類型(integral type)
- 浮點類型(floating type)

術語整數類型包括下述C++類型範疇:

- 有符號整數類型 (signed char, short, int, long),
- 無符號整數類型(unsigned char, unsigned short, unsigned int, unsigned long),
- 字元類型char與寬字元類型wchar_t
- 布林類型bool。

術語浮點類型包括C++的float, double, and long double類型.

術語枚舉類型包括各種枚舉類型，即命名的常量值(named constant values)的集合.

術語指標類型包括下述C++類型範疇:

- 空指標pointer-to-void (void *),
- 對象指標pointer-to-object與指向靜態數據成員的指標pointer-to-static-member-data (都是形如為T*，其中T是對象類型),
- 函數指標pointer-to-function與指向靜態成員函數的指標pointer-to-static-member-function (都是形如T (*)(...)，T是函數的返回值的類型).

術語指標到成員類型包括下述C++類型範疇:

- 指標到非靜態數據成員(pointer-to-nonstatic-member-data), 形如T C::* 表示指向類C的類型為T的數據成員的指標。
- 指標到非靜態成員函數(pointer-to-nonstatic-member-functions), 形如T (C::*)(...) 表示指向類C的返回值類型為T的成員函數的指標.

### POD類類型

POD類類型是指聚合類(aggregate classes, 即POD-struct types)與聚合union (POD-union types)，且不具有下述成員:

- 指針到成員類型的非靜態數據成員(包括陣列)。
- 非POD類類型的非靜態數據成員(包括陣列)。
- 引用類型的(reference type)非靜態數據成員。
- 使用者定義的拷貝與賦值算子。
- 使用者定義的析構函數。

術語聚合是指任何的陣列或者類，且不具有下述特徵:

- 使用者定義的構造函數。
- 私有或保護的非靜態數據成員。
- 基類。
- 虛函數。

可見，POD類類型就是指class、struct、union，且不具有使用者定義的構造函數、析構函數、拷貝算子、賦值算子；不具有繼承關係，因此沒有基類；不具有虛函數，所以就沒有虛表；非靜態數據成員沒有私有或保護屬性的、沒有引用類型的、沒有非POD類類型的（即嵌套類都必須是POD）、沒有指針到成員類型的（因為這個類型內含了this指針）。

### C++11

C++11把情況推廣為兩種：

類型是平凡的（trivial），則可以靜態初始化、可以用memcpy直接複製數據而不是必須用copy構造函數。其生存期始於它的對象的存儲被定義，無須等到構造函數完成。平凡class或結構必須滿足：

- 有平凡的預設構造函數，可用這樣的默認語法：(SomeConstructor = default)
- 有平凡的copy與move構造函數，可用默認語法.
- 有平凡的copy與move運算符，可用默認語法.
- 有平凡的destructor，不能是虛函數.

構造函數是平凡的，僅當類沒有虛成員函數也沒有虛基類。Copy/move運算符是平凡的，僅當沒有靜態數據成員。

類型是標準布局的（standard-layout）意味著它是有序的並且安排其成員兼容於C語言。這要求滿足：

- 沒有虛函數
- 沒有虛基類
- 所有非靜態數據成員有相同的訪問控制(public, private, protected)
- 所有非靜態數據成員，包括在任何基類中的，存在於類繼承體系中的一個類中
- 上述規則適用於所有基類與類繼承體系中的所有非靜態數據成員
- 沒有同一類型的基類型被定義為第一個非靜態數據成員

一個class/struct/union是POD，當它是平凡的、標準布局的，所有數據成員是POD.

分為兩個概念，對象可以不滿足其中一個但是滿足另外一個。例如，類有複雜的move與copy構造函數，因此不是平凡的，但可能是標準布局因此能與C程序互操作。類似地，一個類的有public與private的非靜態數據成員，因此不是標準布局，但可以是平凡的因此可以memcpy操作。

## 用途

POD類型在原始碼兼容於ANSI C時非常重要。POD對象與C語言的對應對象具有共同的一些特性，包括初始化、複製、記憶體布局、尋址。

一個例子是下述C++的new表達式中的對象初始化，POD與non-POD的區別:

表達式｜POD類型T｜non-POD類型T

new T｜不初始化｜預設初始化

new T｜總是預設初始化

new T(x)｜總是調用構造函數初始化

因此，non-POD類型的對象或陣列總是被初始化；而POD類型的對象或陣列可能未被初始化.

其它與POD相關的C++特性:

- 記憶體布局——POD對象的組成字節是連續的.

"POD-struct ... types are layout-compatible if they have the same number of members, and corresponding members (in order) have layout-compatible types".

POD-union ... types are layout-compatible if they have the same number of members, and corresponding members (in any order) have layout-compatible types".

- 初始化——對於non-const POD對象，如果沒有初始化聲明時，具有不確定的初值(indeterminate initial value) . POD對象的預設初始化為0值. 靜態POD對象初始化為給定的初值，如果是局部靜態POD對象，在進入所在作用域之前初始化§6.7, ¶4; 對於非局部靜態POD對象，在任何動態初始化之前賦予初值.
- 拷貝——POD對象可直接拷貝(例如用memcpy)到其它字符陣列或相同POD類型的對象，保持其值不變。POD類型可以用作標準模板字串類的字符. 由於這個原因，函數的返回值如果是non-POD類型，則不能通過寄存器傳遞函數的返回值。
- 尋址——一個POD對象的地址可以是一個地址常量表達式；一個對POD成員的引用可以是一個引用常量表達式. 一個POD-struct對象的指針，適合用reinterpret_cast轉換到它的初始值.

## POD JAVA

JAVA中，一些開發者認為POD類型是符合沒有public成員且沒有方法的類，比如data transfer object。其實不使用事件句柄並且不實現除getter和setter之外的附加方法的POJO（只含有getter和setter的類）和JAVA Bean也屬於POD。但不管怎麼樣，POJO和JAVA Bean已經有了封裝，已經違反了POD的定義了。