[英]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 ++中, struct
和class
基本上是相同的,唯一的區別是一個成員(和繼承) struct
是public
默認,而具有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
始終是固定大小的。 有幾種方法可以克服此限制:
char[1]
“未綁定”數組作為最后一個成員,並為堆上的struct
本身分配內存。 union
為重疊的成員節省一些空間。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.