【譯】C++ POD的理解(2):PODs

##什麼是PODs以及它的特殊性 在C++標準中的正式定義(C++03 9 §4):c++

一個POD結構體是一個沒有非靜態的non-POD-struct、non-POD-union(或者這些類型的數組)或者引用類型的數據成員的aggregate類型,而且沒有用戶自定義的拷貝賦值操做和用戶自定義的析構函數(譯者注:這句話讀起來很繞,在此解釋一下,POD類型首先是一個aggregate類型,這個aggregate類型中不能含有非靜態的non-POD結構體或者聯合體,也不能含有用戶自定義的拷貝賦值函數和用戶自定義的析構函數)。相似的,一個POD聯合體是一個沒有非靜態的non-POD-struct、non-POD-union(或者這些類型的數組)或者引用類型的數據成員的aggregate類型,而且沒有用戶自定義的拷貝賦值操做和用戶自定義的析構函數。一個POD類要麼是POD結構體,不然是POD聯合體。

這個看起來更難以理解。如今讓咱們把聯合體剝離,換一種更清晰的說法:數組

若是一個aggregate類型不含用戶自定義的拷貝賦值函數和析構函數,不含有非靜態的non-POD類型的結構體和no-POD類型結構體的數組,不含有引用成員,則這個aggreagate類型爲POD類型。

這個定義是什麼意思呢(POD就是Plain Old Data)?安全

  • 全部的POD類型都是aggregates,反過來講,若是一個類不是aggregate,則它確定不是POD;
  • 與struct同樣,class也能夠是pod,儘管這兩種狀況下的標準術語都是POD-struct;
  • 就像aggregate的例子同樣,不受static成員影響。

舉例:函數

struct POD
{
  int x;
  char y;
  void f() {} //no harm if there's a function
  static std::vector<char> v; //static members do not matter
};

struct AggregateButNotPOD1
{
  int x;
  ~AggregateButNotPOD1() {} //user-defined destructor
};

struct AggregateButNotPOD2
{
  AggregateButNotPOD1 arrOfNonPod[3]; //array of non-POD class
};

POD類、POD聯合體、標量類型以及上述全部類型的數組被統稱爲POD類型。 PODs有不少特殊的地方,我這裏僅舉幾個例子:佈局

  • POD類型最接近C語言中的結構體。與他們不一樣的是,PODs能夠擁有成員函數和任意類型的static成員變量,可是上述二者都不會改變對象的內存佈局。因此若是你想或多或少寫一個能夠被C甚至是.NET調用的動態庫,你應該嘗試讓全部的輸入和返回類型都是POD類型;
  • 在非POD類對象的生命週期內是從構造函數完成到析構函數完成。對於POD類來講,對象的生命週期是從對象的存儲被佔用開始到存儲被釋放或者重用結束;
  • 對POD類型的對象來講,C++標準保證了當你使用memcpy將對象的內容拷貝到一個char或者unsigned char的數組中再使用memcpy拷貝回來時,對象的內容保持不變。值得注意的是對於非POD類型來講,C++沒有這樣的保證。固然,你可使用memcoy在POD對象之間安全地拷貝。下面的例子中假設T是POD類型:
#define N sizeof(T)
char buf[N];
T obj;                          // obj initialized to its original value
memcpy(buf, &obj, N);           // between these two calls to memcpy,
                                // obj might be modified
memcpy(&obj, buf, N);           // at this point, each subobject of obj of scalar type
                                // holds its original value
  • goto語句。你可能知道,經過goto語句從某個變量還不存在的做用域的點上跳到它已經存在的做用域的點是非法的(編譯器會報出錯誤)。這個限制僅適用於非POD類型的變量。在下面的例子中f()是不合法的,g()是合法的。值得注意微軟的編譯器對於這條規則過於寬容--在全部例子中僅僅給出警告。
int f()
{
  struct NonPOD {NonPOD() {}};
  goto label;
  NonPOD x;
label:
  return 0;
}

int g()
{
  struct POD {int i; char c;};
  goto label;
  POD x;
label:
  return 0;
}
  • C++標準保證了POD類型的開頭不會填充任何內容填充。換句話說,若是一個POD類型A的第一個成員是T類型的,你能夠安全得從A*到T*進行reinterpret_cast,而且得到一個指針,反之亦然。

##結論 理解POD的確切含義是很重要的,由於正如你所看到的,許多語言特性對它們的行爲是不一樣的。this

相關文章
相關標籤/搜索