Advertisement

Size of enum class? (c++)

Started by September 03, 2018 02:50 PM
9 comments, last by Bregma 6 years, 2 months ago

Hi!

If i do this:


enum class action { hold, attack, defend};

action myAction[100];
int myAction2[100];

1. Do myAction and myAction2 take the exact same amount of memory? I load and save chunks of memory to/from disk and don't want any nasty suprises down the road. 
2. Put it in another way: can the array of enum classes (myAction) be saved loaded from memory/work the same way in memory as an array of a "primitive" class:


class primitiveClass{
	int data[10];
	float stuff[25];
};

primitiveClass normal[100]; // this I can save/load without trouble

Thanks!

  1. From C++ standard: "For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can represent all the enumerator values defined in the enumeration.". Which means anything between char and long long.
  2. Yes. You can specify the underlying type:
    
    enum action : int {
        hold,
        attack,
        defend
    };

     

Advertisement
27 minutes ago, Zaoshi Kaba said:
  1. From C++ standard: "For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can represent all the enumerator values defined in the enumeration.". Which means anything between char and long long.
  2. Yes. You can specify the underlying type:
    
    
    enum action : int {
        hold,
        attack,
        defend
    };

     

Also for scoped enums, when the type is not specified, it defaults to int.

And as for saving/loading enums, you should be careful when treating them as simple ints. Enums tend to change over time, sometimes you have to put a new enum value somewhere in the middle. It will break the existing save files. You should at least consider  saving them as strings

you mean the "int-value" held in the stored enum would change? So attack would be interpreted as something else (e.g. hold)? That's fine and something i need to keep track on anyway. I just dont want the stored array of enums to change size, thus "moving" following data in memory.

Slightly offtopic, isn't there overhead for memory for classes or enum? Does an array of classes only need the exact memory of the members in the class? So these arrays (array1, array2) take the exact same memory? (i understand the class definition may take some memory, i'm talking about the array of class instances).


class intClass{
   public:
   int myData[5];
   
   void reset(){ myData[3] = 1;};
   int returnSum();
};

int array1[100][5];
intClass array2[100];

 

5 minutes ago, suliman said:

you mean the "int-value" held in the stored enum would change? So attack would be interpreted as something else (e.g. hold)? That's fine and something i need to keep track on anyway. I just dont want the stored array of enums to change size, thus "moving" following data in memory.

Slightly offtopic, isn't there overhead for memory for classes or enum? Does an array of classes only need the exact memory of the members in the class? So these arrays (array1, array2) take the exact same memory? (i understand the class definition may take some memory, i'm talking about the array of class instances).



class intClass{
   public:
   int myData[5];
   
   void reset(){ myData[3] = 1;};
   int returnSum();
};

int array1[100][5];
intClass array2[100];

 

In this particular example they can actually have equal sizes, but generally you should not depend on it because of "padding and alignment " of data members in classes or structures. So it would be a bad design decision to assume something about size of your structure. Upgrading your compiler might change it. Definition itself doesn't require memory.

Advertisement

As everybody said, there's no guarantee they'll be the same size, if you don't use class enums.

One practice I've seen is to put a final member into the enum, like this:


enum action : uint8_t { hold, attack, defend, MAX_ACTION }

and then have hand-hardcoded compile time assertions:


static_assert(action::MAX_ACTION == 3 && sizeof(action) == sizeof(uint8_t), "Did we change a serialised enum?")

Although it seems very redundant, and it is, if you change serialised types, your code will stop compiling and you'll have to take time to think how it broke and what to do about it.

In this example it's a total overkill, don't do it :) But for some more complicated structures, not (only) enums, which are serialised without any reflection, it might be useful.

I can't also recommend enough getting used to using very explicitly sized types like int8_t, uint8_t, int32_t, uint64_t, etc., for everything that goes to disk. Only use int/uint when you know you don't care about their size.

Sorry if this is a bit of a tangent of your original question - but you should start thinking about saving and loading things to a well defined format - it doesnt take much to code and really can be a huge time saver in the future.

Im a big fan of the json format personally - and there are some good lightweight libraries for pretty much any language (built in to some) - but any format like this will work..

A benefit of doing this is usually the save data can be easily formatted to pretty much any other well defined format - such as easily readable text on file which is a huge help for debugging - or binary data chunks that can be stored in online databases. Another benefit is that your save data will likely not only have the ability to be platform agnostic - but even language agnostic.

On 9/5/2018 at 2:47 PM, suliman said:

you mean the "int-value" held in the stored enum would change? So attack would be interpreted as something else (e.g. hold)? That's fine and something i need to keep track on anyway. I just dont want the stored array of enums to change size, thus "moving" following data in memory.

Slightly offtopic, isn't there overhead for memory for classes or enum? Does an array of classes only need the exact memory of the members in the class? So these arrays (array1, array2) take the exact same memory? (i understand the class definition may take some memory, i'm talking about the array of class instances).



class intClass{
   public:
   int myData[5];
   
   void reset(){ myData[3] = 1;};
   int returnSum();
};

int array1[100][5];
intClass array2[100];

 

Half the things the C++ compiler does are just for human sanity.  As far as the computer goes an enum is an int (of some size), an int is an enum. There is no table anywhere except possibly during compilation and perhaps one that gets used by the debugger when compiling in debug mode.  There shouldn't really be any overhead over using raw integers. 

What he Mr.flatiron  means by " Enums tend to change over time" is simply this.... given your example of:


enum class action { hold, attack, defend};

We have hold == 0, attack == 1 and defend == 2 by default.  These are values assigned by the compiler.  If you then add say "retreat" after hold we have:


enum class action { hold, retreat, attack, defend};

Now we have hold == 0, retreat == 1, attack == 2 and defend == 3.  So if you had converted these to integers and written them out to a file and then changed your enum, they would be wrong when you read them back in. Again an enum is nothing special. It's just a place holder for an integer.

On 9/5/2018 at 8:53 AM, pcmaster said:

I can't also recommend enough getting used to using very explicitly sized types like int8_t, uint8_t, int32_t, uint64_t, etc., for everything that goes to disk. Only use int/uint when you know you don't care about their size.

QFE.  If you care at all about size, offset, or marshalling/unmarshalling, an enum is inappropriate.  You need an integer of known fixed size, and you need to be able to convert between the two.  I've just been dealing with a customer who lost a (multi-million-dollar-valued) safety certification because they thought they knew what they were doing by using enums in a hardware interface (this is obviously not in the game development industry).  Do not treat enums as integers.  If you treat enums as integers, you don't know what you're doing.  If you don't know what you;re doing when you're writing software, you're going to end up sad sooner or later.

Stephen M. Webb
Professional Free Software Developer

This topic is closed to new replies.

Advertisement