C++11 POD类型
1、首先是平凡的(trival)定義,通常一個平凡的類或者結構體需要滿足以下定義
(1).擁有平凡的默認構造函數和析構函數。默認的意思就是由編譯器為我們自動生成的,不許是我們自己定義的,而一旦定義了構造函數,即使函數體里沒有任何代碼,那么該構造函數也不在是平凡的,但是由于c++11提供了default,也可以是自己定義的加=default。
(2).擁有平凡的拷貝構造函數和移動構造函數。默認的意思同上,也可以使用=default。
(3).擁有平凡的拷貝賦值運算符和移動賦值運算符。
(4).不能包含虛函數和虛基類。
C++11中,我們使用模版類std::is_trivial<T>::value來判斷數據類型是否為平凡類型。
#include "stdafx.h" #include <iostream>using namespace std;class A { A(){} }; class B { B(B&){} }; class C { C(C&&){} }; class D { D operator=(D&){} }; class E { E operator=(E&&){} }; class F { ~F(){} }; class G { virtual void foo() = 0; }; class H : G {}; class I {};int _tmain(int argc, _TCHAR* argv[]) {std::cout << std::is_trivial<A>::value << std::endl; //有不平凡的構造函數std::cout << std::is_trivial<B>::value << std::endl; //有不平凡的拷貝構造函數std::cout << std::is_trivial<C>::value << std::endl; //有不平凡的拷貝賦值運算符std::cout << std::is_trivial<D>::value << std::endl; //有不平凡的拷貝賦值運算符std::cout << std::is_trivial<E>::value << std::endl; //有不平凡的移動賦值運算符std::cout << std::is_trivial<F>::value << std::endl; //有不平凡的析構函數std::cout << std::is_trivial<G>::value << std::endl; //有虛函數std::cout << std::is_trivial<H>::value << std::endl; //有虛基類std::cout << std::is_trivial<I>::value << std::endl; //平凡的類return 0; }?
2.接下來是標準布局的定義(1).所有非靜態成員擁有相同的訪問級別,(訪問級別就是public,private,protected)
struct t1{ private :int a; public:int b; }; //不滿足標準布局,因為a,b訪問級別不同。(2).在類和結構體繼承時需要滿足以下兩個情況之一:
派生類中有非靜態類,那么這個派生類只能有且只有一個僅包含了靜態成員的基類。
基類有非靜態成員,那么派生類中不允許有非靜態成員。
(這兩句話看著挺繞口,其實就是在說明一個事實,關于非靜態數據的事實,派生類中有非靜態的數據那么它的基類只能是只有靜態的,而且基類只能有一個。如果基類有非靜態的, 那么派生類就不能有非靜態的。有種蹺蹺板的感覺,非靜態的對面坐著的是靜態,父子類就 是坐在蹺蹺板的兩端這種對應關系。)(3).類中第一個非靜態類型與基類不是同一個類型。比如
struct A:B{B b;int c; } //不符合這個條件。因為A中第一個成員是基類B類型的(4).沒有虛類和虛基類(與trival中重復)
(5).所有非靜態數據成員都符合標準布局的要求,這其實就是一個遞歸的定義。
C++11中,我們使用模版類std::is_standard_layout<A>::value來判斷類型是否是一個標準布局類型。
?
所以在C++11中,POD就是滿足平凡的(trival)和標準布局(standard layout)這兩個方面。 可以使用<type_traits>中的is_pod<T>::value判斷T是不是POD類型的。 #include <iostream>using namespace std;class A { private:int a; public:int b; };class B1 {static int x1; };class B2 {int x2; };class B : B1, B2 {int x; };class C1 {}; class C : C1 {C1 c; };class D { virtual void foo() = 0; }; class E : D {}; class F { A x; };int main() {std::cout << std::is_standard_layout<A>::value << std::endl; //違反定義1,成員a和b具有不同的訪問權限std::cout << std::is_standard_layout<B>::value << std::endl; //違反定義2,繼承樹有兩個(含)以上的類有非靜態成員std::cout << std::is_standard_layout<C>::value << std::endl; //違反定義3,第一個非靜態成員是基類類型std::cout << std::is_standard_layout<D>::value << std::endl; //違反定義4,有虛函數std::cout << std::is_standard_layout<E>::value << std::endl; //違反定義5,有虛基類std::cout << std::is_standard_layout<F>::value << std::endl; //違反定義6,非靜態成員x不符合標準布局類型return 0; } View Code #include <iostream> #include <cstring>using namespace std;class AA { public:int x;double y; };int main() {if (std::is_pod<AA>::value) {cout << "before" << endl;AA aa;aa.x = 10;aa.y = 20.0f;cout << aa.x << " " << aa.y << endl;size_t size = sizeof(aa);char *p = new char[size];memcpy(p, &aa, size);AA *pA = (AA*)p;cout << "after" << endl;cout << pA->x << " " << pA->y << endl;delete p;}return 0; } View Code?
說了這么多,那么為什么我們需要POD這種條件滿足的數據呢?
(1).可以使用字節賦值,比如memset,memcpy操作
(2).對C內存布局兼容。
(3).保證了靜態初始化的安全有效。
總結
以上是生活随笔為你收集整理的C++11 POD类型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jquery之仿京东菜单
- 下一篇: 倚天遇到屠龙:LightGBM VS x