關於C 中的POD型別

2021-07-08 17:30:39 字數 4682 閱讀 1292

最近碰到筆試題中有關於pod型別的問題,看了好多部落格對此還是沒有理解透徹,總結在此便於日後學習.

pod全稱plain old data。通俗的講,乙個類或結構體通過二進位制拷貝後還能保持其資料不變,那麼它就是乙個pod型別。

平凡的定義:

1. 有平凡的建構函式;

2. 有平凡的拷貝建構函式;

3. 有平凡的移動建構函式;

4. 有平凡的拷貝賦值運算子;

5. 有平凡的移動賦值運算子;

6. 有平凡的析構函式;

7. 不能包含虛函式;

8. 不能包含虛基類。

#include using namespace std;

class a };

class b };

class c };

class d };

class e };

class f };

class g ;

class h : g {};

class i {};

int main(int argc, char* argv)

標準布局的定義:

1. 所有非靜態成員有相同的訪問許可權;

2. 繼承樹中最多只能有乙個類有非靜態資料成員;

3. 子類的第乙個非靜態成員不可以是基類型別;

4. 沒有虛函式;

5. 沒有虛基類;

6. 所有非靜態成員都符合標準布局型別。

#include using namespace std;

class a

;class b1

;class b2

;class b : b1, b2

;class c1 {};

class c : c1

;class d ;

class e : d {};

class f ;

int main(int argc, char* argv)

當乙個資料型別滿足了「平凡的定義」和「標準布局」,我們就認為它是乙個pod資料——可以通過std::is_pod來判斷乙個型別是否為pod型別。

如文章開頭說的,乙個pod型別是可以進行二進位制拷貝的,看看下面的例子——

class a

;class b1

;class b2

;class b : b1, b2

;class c1 {};

class c : c1

;class d ;

class e : d {};

class f ;

int main(int argc, char* argv)

可以看到,對乙個pod型別進行二進位制拷貝後,資料都成功地遷移過來了。

pod是c++中乙個很重要的概念,而且非常容易被忽視,其主要的用處是,pod物件(特別是陣列)在進行複製的時候,不必呼叫物件的複製建構函式或者operator=,可以直接採用memcpy函式來提高效率。如何知道乙個類變數或者結構體變數是否pod型別的呢? c++11中完全可以使用std::is_pod<> ,或者std::is_trivial<> 來檢測,但是如果不支援c++11或者處於另外的考慮我們怎麼辦呢?,有時候我們自己也可以想個其他辦法來檢測pod

在中作者提到了另一種方法鑑定是否為pod型別:

今天看到了乙個方法,讓我眼前一亮,它能夠編譯期確定乙個型別是否為pod型別。但是,卻不能利用該特性進行型別萃取,只能判斷某一型別是否為pod型別,如果不是,編譯器報錯。方法如下:

templatestruct must_be_pod

;};

將乙個類作為模板形參傳入,如果其是pod型別,則可以放入union中,否則,不是pod型別。這裡其實,是將pod型別等價於可以放入union中的物件。c++中,可以放入union中的物件,是其本身以及其所有的成員變數都沒有預設建構函式的物件

但是上面的例子僅僅適用於非c++11中,在c++03中,並非任意的型別都能做為union的成員。比方說,帶有non-trivial 建構函式的型別就不能是union的成員。在新的標準裡,移除了所有對union的使用限制,除了其成員仍然不能是引用型別。這一改變使得union更強大,更有用,也易於使用。例如,

struct point

point(int x, int y): x_(x), y_(y) {}

int x_, y_;

};union

;

那麼c++11中的一些型別是否是pod型別呢?測試如下:

int main(void)

程式輸出:

int: is_trivial: 1 is_standard_layout: 1 is_pod: 1

string: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(string): 4

array: is_trivial: 1 is_standard_layout: 1 is_pod: 1

array: is_trivial: 0 is_standard_layout: 1 is_pod: 0

pair: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(pair): 8

pair: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(pair): 8

vector: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(vector): 12

vector: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(vector): 12

deque: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(deque): 40

deque: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(deque): 40

list: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(list): 8

list: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(list): 8

vector>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(vector>): 12

vector>: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(vector>): 12

set: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(set): 24

set: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(set): 24

map: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(map): 24

map: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(map): 24

unordered_set: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unorder_set): 24

unordered_set: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unorder_set): 24

unordered_map: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unorder_map): 24

unordered_map: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unorder_map): 24

shared_ptr: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(shared_ptr): 8

unique_ptr: is_trivial: 0 is_standard_layout: 1 is_pod: 0 sizeof(unique_ptr): 4

結論:內建型別(如: int, float),array是pod型別

pod型別是遞迴的,array就不是pod型別,因為string不是

所有測試型別包括:pair(tuple), vector, list, deque, set, map, unordered_set, unordered_map, shared_ptr, unique_ptr

都滿足 is_standard_layout但是不滿足is_trivial,因此也不滿足is_pod型別。

unique_ptr具有和普通指標一樣大小,大多數時候應該使用它(當然還有其它原因: 如unique效能更好等等),而不是shared_ptr。

測試參考:

關於C 中的POD型別

pod型別 plain old data 我第一次是在morden c design中看到的。說實話這確實是一本好書,裡面的技巧讓人嘆為觀止。裡面提到了pod型別,該型別相容c語言的struct,主要的用處是,pod物件 特別是陣列 在進行複製的時候,不必呼叫物件的複製建構函式或者operator ...

關於C 中POD型別的解析

c 98 1.8 5 給出的定義 將物件的各位元組拷貝到乙個位元組陣列中,然後再將它重新拷貝到原先的物件所佔的儲存區中,此時該物件應該具有它原來的值。imperfect c 一書中給出的定義和一些特性利用 1 所有標量型別 pod結構型別 pod聯合型別 以及這幾種型別的陣列 const volat...

c 的POD型別詳解

最早看到pod plain old data 型別,是在imperfect c 裡。我覺得這是一本把我帶到c 世界裡的一本很重要的書。書裡是這樣解釋pod的 1 所有標量型別 基本型別和指標型別 pod結構型別 pod聯合型別 以及這幾種型別的陣列 const volatile修飾的版 本都是pod...