簡體   English   中英

普通布局 vs. 標准布局 vs. POD

[英]trivial vs. standard layout vs. POD

通俗地說,平凡類型、標准布局類型和 POD 之間有什么區別?

具體來說,我想確定new T是否與new T()對於任何模板參數T 我應該選擇is_trivialis_standard_layoutis_pod哪一個類型特征?

(作為一個附帶問題,可以在沒有編譯器魔法的情況下實現這些類型特征中的任何一個嗎?)

我不認為它可以用真正外行的術語來完成,至少沒有很多額外的解釋。 一個重點是靜態與動態初始化,但向外行解釋這本身就是幾頁......

POD 是在 C++98 中(錯誤)定義的。 確實涉及兩個獨立的意圖,都沒有很好地表達:1)如果您在 C++ 中編譯 C 結構聲明,您得到的應該與您在 C 中擁有的相同。2)POD 只需要/使用靜態(非動態)初始化。

C++0x/11(幾乎)完全放棄了“POD”名稱,轉而支持“平凡”和“標准布局”。 標准布局旨在捕捉第一個意圖——創建與您在 C 中獲得的布局相同的內容。瑣碎旨在捕捉對靜態初始化的支持。

由於new Tnew T()處理初始化,您可能需要is_trivial

我不確定是否需要編譯器魔法。 我的直接反應可能是肯定的,但知道人們用 TMP 做過的一些事情,我很難確定有人也不能這樣做......

編輯:例如,也許最好只引用 N3290 的示例:

struct N { // neither trivial nor standard-layout
   int i;
   int j;
    virtual ~N();
};

struct T { // trivial but not standard-layout
    int i;
private:
    int j;
};

struct SL { // standard-layout but not trivial
    int i;
    int j;
    ~SL();
};

struct POD { // both trivial and standard-layout
    int i;
    int j;
};

毫無疑問,您可以猜到, POD也是一個 POD 結構。

對於 POD 類型new T()是值初始化(將對所有成員進行值初始化),而new T不會初始化成員(默認初始化)。 有關不同形式的初始化之間的差異, 請參閱此問題 底線:你需要is_pod

布局是類、結構或聯合對象的成員在內存中的排列方式。 這可能是連續的或不連續的。通常語言指定布局,但如果有像虛函數、虛擬基類等的東西,那么編譯器可以自由選擇布局,這可能不是連續的。 這導致了幾個問題,我們無法適當地序列化對象或傳遞給用其他語言(如 C)或函數(如 memcopy)編寫的程序,因為我們無法可靠地復制數據,因為它不在連續位置。

為了使編譯器和c++程序能夠支持上述操作,c++為簡單結構和類引入了3個類別。

瑣碎的

如果類或結構遵循以下規則,則它是微不足道的:

  • 沒有虛函數或虛基類
  • 沒有用戶定義的構造函數/運算符/析構函數
  • 基類應該是微不足道的
  • 所有的班級成員都應該是平凡的

如果一個類是微不足道的,那么它的布局是連續的,但可能會有相應的填充,編譯器可以自由選擇布局中成員的順序。 因此,即使我們可以對對象進行內存復制,但如果我們將該對象復制到 C 程序中,也是不可靠的。我們可以在同一個類中使用不同的訪問說明符,如果使用參數化構造函數,顯然我們必須指定默認構造函數。 但是如果你想讓這個類保持簡單,那么你應該明確地將構造函數設為默認值。構造函數應該是公共的。

標准布局

  • 沒有虛函數和虛基類
  • 所有非靜態成員都應該具有相同的訪問說明符
  • 所有非靜態成員都應該是標准布局
  • 所有基類都應該是標准布局
  • 基類的所有成員都應該是靜態的
  • 基類和類的第一個非靜態成員的類型不應相同

標准布局定義明確,可以可靠地進行內存復制並適當地傳遞給 C 程序。 此外,標准布局函數可以具有用戶定義的特殊成員函數,如構造函數和析構函數。

POD(普通舊數據)

如果一個類或結構既是平凡的又是標准的布局,那么它被稱為 POD。每個成員都按照聲明對象時指定的順序存儲。 POD 類應該具有 POD 非靜態數據成員。POD 類可以可靠地復制或傳遞給 C 程序。

C++ 程序的類是平凡的、標准的布局,因此是 POD。

#include<iostream>
#include<type_traits>
class xyz
{
public:
    int a;
    int b;
    xyz() = default;
    xyz(int x, int y) :a(x), b(y) {}
};
int main() {
    std::cout << std::is_trivial<xyz>() << std::endl;//true
    std::cout << std::is_standard_layout<xyz>() << std::endl;//true
    std::cout << std::is_pod<xyz>() << std::endl;//true
}

文字類型

對於文字類型,可以在編譯時確定布局。文字類型的示例是 void、標量類型(例如 int 、 float 等)、引用、void 數組、標量類型或引用以及具有簡單析構函數的類,以及一個或多個不是移動或復制構造函數的 constexpr 構造函數。 此外,它的所有非靜態數據成員和基類必須是文字類型而不是 volatile

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM