簡體   English   中英

C ++結構成員內存分配

[英]C++ struct member memory allocation

我有一個看起來像這樣的結構:

struct rtok {
    char type;
    std::string val;
    bool term;
};

我正在編寫一個簡單的解釋器,而這種“ rtok”結構就是我表示令牌的方式。 我有一個“ rtoks”向量,可以迭代生成解析樹。

我的問題是,如果我的結構中有3個成員,而我只給1個成員賦值,其他成員是否還會占用內存?

我的意思是,如果我將“ val”設置為等於“ test”,我的令牌將僅占用4個字節還是占6個字節? (“ val”為4個字節,類型為1個字節,術語為1個字節)

假設您沒有其他成員或虛函數,則您的結構將始終占用sizeof(char) + sizeof(string) + sizeof(bool) + possible padding string部分為自己分配了一塊內存,在破壞時會對其進行分配。 但是,從技術上講,此內存不是為struct分配的內存的一部分。

因此,無論您為成員提供(或忽略)值是多少,該結構都將始終具有相同的大小。

不用擔心,這將花費比您想象的更多的時間。

有兩個因素:數據對齊和內部類型實現。 首先,關於數據對齊:結構中的所有類型都是自然對齊的,這意味着char可以位於任何地址,但是void*可能需要對齊4或8,具體取決於體系結構。

因此,如果我們猜測,則std :: string在內部僅使用char*來使您保持字符串在x32上的布局將是:

struct rtok {
  char type;
  char* val; // here char * for simplicity
  bool term;
};

sizeof(rtok)運算符將提供12個字節,而不是6個字節,並且內存占用量將類似於:

00: type (one byte)
01: padding
02: padding
03: padding
04-07: char * (4 bytes)
08: term (one byte)
09-0a: padding (3 bytes)

現在,如果將char*替換為std::string ,我們會發現結構大小已經增大,因為sizeof(std::string)通常大於4個字節。

但是,我們還沒有計算字符串值本身...在這里,我們進入堆管理和分配領域。

用於存儲值的內存是在堆上分配的,並且代碼通常會根據需要進行請求,因此對於10個字符的字符串,它將是11個字節(10個字符加上1個字節(對於空終止符))。

而且,堆具有自己的復雜結構,其中包括小塊堆等。實際上,這意味着最小的消耗量約為16個字節或更多。 該數量不是您可以使用的數量,該數量用於管理堆內部結構,並且唯一可用的數量可以少至1個字節。

如果將所有內容加起來,就會發現即使計划僅使用兩個字符加類型,消耗的內存量也將大得多。

給定類型的struct始終具有相同的大小。 這是標准的保證。 (sum of sizes of members + possible padding for alignment for each member), and they are to be in in memory (same order of member definitions in containing struct definition)": 當您定義一個struct ,您說的是“我有一個具有的對象(成員總和+每個成員對齊所需的填充),並且它們在內存中的應與 (包含struct定義)“:

(N4296)9.2
A simple example of a class definition is / 12 [ 類定義的一個簡單示例是

struct tnode {
  char tword[20];
  int count;
  tnode* left;
  tnode* right;
};

其中包含20個字符的數組,一個整數和兩個指向相同類型對象的指針。 [...]-結束

/ 13分配具有相同訪問控制(第11條)的(非聯盟)類的非靜態數據成員,以便以后的成員在類對象中具有更高的地址。 未指定具有不同訪問控制的非靜態數據成員的分配順序(第11條)。 實施一致性要求可能會導致兩個相鄰成員不能彼此立即分配; 管理虛擬功能(10.3)和虛擬基類(10.1)的空間要求也可能如此。

" qualifier. 請注意“ ”限定詞。 如果您的結構中混合了具有不同訪問說明符的數據成員,則布局可能不是您所期望的,除了保證給出類似以下內容之外:

public:
   some_type public_1;
private:
   some_type private_1;
public:
   some_type public_2;

public_2地址將比public_1 除此之外-未指定。 private_1可以位於較低或較高的地址。

關於您的其他問題(在評論中提出):

那么,使用類而不是結構會更好嗎?

在C ++中, structclass基本上是相同的,唯一的區別是一個成員(和繼承) structpublic默認,而具有class它們private默認。 在標准的注釋和示例中,這變得更加清楚:

§3.1聲明和定義[basic.def]
In some circumstances, C ++ implementations implicitly define the default constructor (12.1), copy constructor (12.8), move constructor (12.8), copy assignment operator (12.8), move assignment operator (12.8), or destructor (12.4) member functions. / 3 [ 在某些情況下,C ++實現會隱式定義默認構造函數(12.1),復制構造函數(12.8),移動構造函數(12.8),復制賦值運算符(12.8),移動賦值運算符(12.8)或析構函數(12.4)成員函數。 ] [ given ] [ 給定

#include <string>
struct C {
    std::string s; // std::string is the standard library class (Clause 21)
};
int main() {
    C a;
    C b = a;
    b = a;
}

該實現將隱式定義函數以使C的定義等效於

struct C {
    std::string s;
    C() : s() { }
    C(const C& x): s(x.s) { }
    C(C&& x): s(static_cast<std::string&&>(x.s)) { }
    // : s(std::move(x.s)) { }
    C& operator=(const C& x) { s = x.s; return *this; }
    C& operator=(C&& x) { s = static_cast<std::string&&>(x.s); return *this; }
    // { s = std::move(x.s); return *this; }
    ~C() { }
};

] ]

請注意,標准中的示例使用struct而非class來說明非POD structs這一點。 當您認為標准中的struct定義在第9節“類”中時,這一點更加清楚。

如前所述, struct始終是固定大小的。 有幾種方法可以克服此限制:

  1. 存儲指針並為其分配堆內存。
  2. 使用char[1] “未綁定”數組作為最后一個成員,並為堆上的struct本身分配內存。
  3. 使用union為重疊的成員節省一些空間。

暫無
暫無

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

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