Jump to content
  • Advertisement
Sign in to follow this  
Alundra

[c++] Enum, sizeof

This topic is 2175 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

1. Enum

 

Is it more safe to set value for all values of the enum or the default value is safe ?

Is it possible to safely use sizeof to serialize an enum ?

 

2. Sizeof

 

I have a custom array class and in the SetCapacity function I do a for loop :

for( UInt32 i = 0; i < m_Size; ++i )
     m_Data[ i ] = Temp[ i ];

If I replace that with a memcpy :

std::memcpy( m_Data, m_Temp, m_Size * sizeof( T ) );

All works for class who doesn't have pointer but if the class has a pointer like a string, I have a crash.

Is it because the pointer who is an array of data who is undefined-size, the "operator =" needs to be called ?

 

Thanks

Edited by Alundra

Share this post


Link to post
Share on other sites
Advertisement

Is it more safe to set value for all values of the enum or the default value is safe ?
Is it possible to safely use sizeof to serialize an enum ?

 

If no value is specified, the enumeration values will take ordinal values 0, 1, 2, .. in the order they are in in the source code. If one value N is specified for one value, all successive values will take ordinal values N + 1, N + 2, ... you can also specify a custom value for each of them should you find the need to. So it's not "more safe", it's just up to you. An enum is supposed to give express a set of distinct states so you shouldn't need to know about the underlying index in general unless you are doing stuff like serialization or other low-level things.

 

Unsure what you mean by using sizeof to serialize an enum. If you mean its size in memory, I think it's defined as an int, and hence platform-dependent, so no, it is not safe and you should cast it to a known-size type such as uint32_t.

 

 

All works for class who doesn't have pointer but if the class has a pointer like a string, I have a crash.
Is it because the pointer who is an array of data who is undefined-size, the "operator =" needs to be called ?

 

It's possible you are freeing your objects after having copied their pointers (either by accident or by design e.g. your object falls out of scope). In this case, yes, you should maintain the reference by using the class's copy constructor or modify your design such that the pointer to the object remains valid even when the original array is deleted.

Share this post


Link to post
Share on other sites

1. Enum

Is it more safe to set value for all values of the enum or the default value is safe ?

It depends. Explicitly settings the values can be good if the actual value really matters (for example, a network protocol). That way you can rearrange elements in the enum without their values changing. It might also help with debugging (for example, you see a value 17, and by looking at your enum, you can know which enum element it's equal to). For other things (where the actual value isn't as important), not setting the values explicitly can be cleaner and can avoid some bugs (for example, if you accidentally mistype or misassign an enum value). If you don't specify the values, the first one has value of 0, and they each increment by one thereafter. So the actual values are well defined so you won't be invoking any weird/undefined behavior if you don't explicitly give the values, however, in some situations you might need/want to explicitly assign values instead of use the default values.

 

Is it possible to safely use sizeof to serialize an enum ?

Sure, as long as the code that reads it also has the exact same enum size.

 

2. Sizeof

 

I have a custom array class and in the SetCapacity function I do a for loop :


for( UInt32 i = 0; i < m_Size; ++i )
     m_Data[ i ] = Temp[ i ];

If I replace that with a memcpy :

std::memcpy( m_Data, m_Temp, m_Size * sizeof( T ) );

All works for class who doesn't have pointer but if the class has a pointer like a string, I have a crash.

Is it because the pointer who is an array of data who is undefined-size, the "operator =" needs to be called ?

More or less, yes. The pointer value is copied (not the data it points to), which means now you have multiple pointers pointing to the same thing. This is bad, because each object might think it owns the data it points to, but in reality they are both pointing to the same thing (so who really has ownership?). When one object is destroyed, or tries to modify the data, it will affect the other object too, which is just begging for some nasty crash.

 

This is why C++ has std::copy(). It doesn't just copy raw blocks of memory; it copies actual objects, and makes sure things are copied correctly.

Share this post


Link to post
Share on other sites

Sure, as long as the code that reads it also has the exact same enum size.

In C++ 11 you can fix the underlying integer type of an enumeration like this:

enum MyEnumeration : unsigned short
{
    MYENUMERATION_FIRST,
    MYENUMERATION_SECOND
}

You can use this if you need to fix the size of your enums for serialization purposes.

Share this post


Link to post
Share on other sites

Sure, as long as the code that reads it also has the exact same enum size.

In C++ 11 you can fix the underlying integer type of an enumeration like this:

enum MyEnumeration : unsigned short
{
    MYENUMERATION_FIRST,
    MYENUMERATION_SECOND
}

You can use this if you need to fix the size of your enums for serialization purposes.

And just a note on top of that: If you really, truly wanted to fix the enum size, you'd use a fixed-width integer: int[8/16/32/64]_t. Specifying unsigned short isn't enough, as the size of a short might differ. But yes, that's a good point to bring up.

Share this post


Link to post
Share on other sites

In C++11, you can specify the underlying integer type of the enum, to be 100% sure of the memory size.

 

Example:

 

enum MyEnum : uint32_t {Alpha, Bravo, Charlie};

Any integer type can be used. It defaults to 'int', whatever that is on your system and compiler.

 

Setting the value of the first enum guarantees that every other enum increments from there.

 

enum MyEnum {Alpha = 0, Bravo /* Guaranteed 1 */, Charlie /* Guaranteed 2 */};

 

Most compilers with auto-default the first enum to 0 even if not specified, but I don't think that's guaranteed by the standard. This may have has changed with C++11.

"If the first enumerator has no initializer, the value of the corresponding constant is zero. An enumerator-definition

without an initializer gives the enumerator the value obtained by increasing the value of the previous enu-merator by one." (uhm, 7.2.2 in N3337 working draft? I'm not sure how to reference the standard properly)
 
A few sentences later it says, "The underlying type can be explicitly specified using enum-base; if not explicitly specified, the underlying type of a scoped enumeration type is int." (7.2.5)
 
The standard also gives this code snippet, when comparing C enums to C++ enums:

enum e { A };
sizeof(A) == sizeof(int) // in C
sizeof(A) == sizeof(e) // in C++
/? and sizeof(int) is not necessarily equal to sizeof(e) ?/

 

So, I would assume sizeof() can be used to serialize enums, though I don't see it explicitly written out.

 

You can download your own copy of the standard. They sell some versions of it for high prices, and other versions they give out free. I'm not sure exactly how it works. Here's N3337 which was what I was quoting from. It's C++11, with some minor last-minute fixes (2012-01-16, only a few months after C++11).

 

[Edit:] In the time spent digging for my copy of the standard, three users posted, and Cornstalks posted twice. laugh.png

Edited by Servant of the Lord

Share this post


Link to post
Share on other sites

Most compilers with auto-default the first enum to 0 even if not specified, but I don't think that's guaranteed by the standard. This may have has changed with C++11.

"If the first enumerator has no initializer, the value of the corresponding constant is zero. An enumerator-definition

without an initializer gives the enumerator the value obtained by increasing the value of the previous enu-merator by one." (uhm, 7.2.2 in N3337 working draft? I'm not sure how to reference the standard properly)
That didn't change in C++11. That same paragraph is found in the C++03 standard too: Section 7.2 paragraph 1: 

If the first enumerator has no initializer, the value of the corresponding constant is zero. An enumerator-definition without an initializer gives the enumerator the value obtained by increasing the value of the previous enumerator by one.
 
 

[Edit:] In the time spent digging for my copy of the standard, three users posted, and Cornstalks posted twice. laugh.png

You're lucky SiCrane didn't post, or else he'd have gotten in a good 10 or so posts before you biggrin.png

 

Edit: as for referencing the standard, there are a few ways. One common way is 7.2/1 (where 7.2 is the section (sometimes prefixed with §), and the number after / (1) is the paragraph). Saying "N3337 working draft" is fine, or some wording like that. Some people do 7.2.1 (treating the paragraph numbers like section numbers, thus putting a decimal point in front of them), but some think that's not ideal because it's hard to see if you're talking about an entire section or a particular paragraph in a section.

Edited by Cornstalks

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!