Memory allocation of C ++ structure elements

I have a structure that looks like this:

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

I am writing a simple interpreter, and this "rtok" structure is how I represent the token. I have a rtoks vector that I repeat to generate a parsing tree.

My question is that if I have 3 members in my structure and I give only 1 member, will the other members take up memory?

What do I mean, if I set "val" to "test", would my token occupy just 4 bytes or occupy 6 bytes? (4 bytes for "val", 1 byte for type, 1 byte for term)

0
c ++ struct memory interpreter
source share
4 answers

Assuming you don't have additional members or virtual functions, your structure will always occupy sizeof(char) + sizeof(string) + sizeof(bool) + possible padding . The string part allocates a piece of memory for itself, which it frees up upon destruction. However, this memory is technically not part of the allocation for struct .

Thus, regardless of the values ​​you give (or omit) for the members, the structure will always be the same size.

+4
source share

Do not worry, it will take significantly more than you think.

There are two factors: data alignment and internal type implementation. First, about data alignment: all types in your structure are naturally aligned, which means that char can be at any address, but void* may require alignment 4 or 8 depending on the architecture.

So, if we assume that std :: string uses just char* internally to save the string in the layout on x32:

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

The sizeof(rtok) would give 12 bytes, not 6, and the memory size would look like this:

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

Now, if we replace char* with std::string , we will see that the size of the structure has increased, since sizeof(std::string) usually larger than 4 bytes.

BUT, we ourselves did not calculate the string value ... And here we find ourselves in the area of ​​heap management and allocation.

Memory for storing the value is allocated on the heap, and the code usually requests as much as it needs, so for a string of 10 characters it will be 11 bytes (10 characters plus 1 byte for the null terminator).

And the heap has its own complex structure with a bunch of small block, etc. In practice, this means that the minimum amount consumed is approximately 16 bytes or more. This amount is not what you can use, this amount is intended to control the internal structures of the heap, and the only amount used can be only 1 byte.

If you put everything together, you will find out that even if you plan to use only two characters plus a type, the amount of memory consumed will be much more.

+2
source share

This type of struct always has the same size. This is a warranty from the Standard. When you define a struct , you say: "I have an object of this size (the sum of the sizes of the members + a possible complement for alignment for each member), and they should be in that order in memory (the same order of the definitions of the members in the definition of the struct )":

(N4296) 9.2
/ 12 [ Example: A simple example of a class definition is

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

which contains an array of twenty characters, an integer and two pointers to objects of the same type. [...] -end example

/ 13 Non-stationary data members of a (non-unitary) class with the same access control (section 11) are allocated so that later members have higher addresses in the class object. The distribution order of non-static data elements with different access control is not specified (clause 11). Requirements for alignment of the implementation can lead to the fact that two neighboring elements will not be distributed immediately one after another; therefore, space may be required to manage virtual functions (10.3) and virtual base classes (10.1).

Note " with the same access control qualifier ." If your structure has a data set with different access specifiers, the layout may not be what you might expect, except for a guarantee that would give something like:

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

public_2 will have a higher address than public_1 . In addition, unspecified. private_1 can be at a lower or higher address.

Regarding your other question (asked in the comments):

Would it be better to use a class instead of a structure?

In C ++, a struct and class are essentially the same, the only difference is that the members (and inheritance) of the default struct are public , while with class they are private by default. This is made even clearer in the note and example of the standard:

Β§3.1. Declarations and Definitions [basic.def]
/ 3 [ Note: In some cases, 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 ) -end note ] [ Example: 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; } 

the implementation will implicitly define functions to make the definition of C equivalent

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

-end example ]

Note that the example from the standard uses struct rather than class to illustrate this point for non-POD structs . This is even more clear when you consider that the definition of struct in the standard is given in Section 9, Classes.

+1
source share

As said before, a struct always has a fixed size. There are several ways to overcome this limitation:

  • Save the pointer and allocate heap memory for it.
  • Use the "unbound" char[1] array as the last member and allocate memory for the struct itself on the heap.
  • Use union to save some space for overlapping elements.
-one
source share

All Articles