最近碰到筆試題中有關於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...