How can I improve this code? (C++ enums)

Started by
21 comments, last by Storyyeller 12 years, 6 months ago
I like fastcall22's solution, except I wouldn't store the index as part of the object. Replacing a simple array with an std::map is a pessimization that I can't understand.
Advertisement
Yeah, that's what I ended up doing. There's no real reason to store a copy of the index.

[source lang='cpp']typedef unsigned int Secret;

namespace Secrets
{
//Order must be kept in sync with array in secret.cpp
enum SecretID : unsigned int {POTATO, NONPOISONOUSMUSHROOM, TM49, OBVIOUSSECRET, DELICIOUSCAKE, BIGDIPPER, NUMSECRETS};

inline Secret begin() {return 0u;}
inline Secret end() {return NUMSECRETS;}

std::string Name(Secret s);
ImgHandle Image(Secret s);
}[/source]
[source lang='cpp']
namespace Secrets
{
struct SecretData{
std::string name;
ImgDataStruct imgdata; //Don't convert to handle until runtime
};

const SecretData data[NUMSECRETS] = {
{"Potato Battery", ImgDataStruct("Secrets/potato.png",0,99,0)},
{"Nonpoisonous Mushroom", ImgDataStruct("Secrets/nonpoisonousmushroom.bmp",255,0,255)},
{"TM49 (Tri Attack)", ImgDataStruct("Secrets/tm49.bmp",0,255,0)},
{"Very Obvious Secret", ImgDataStruct("Secrets/obvioussecret.bmp",0,255,0)},
{"Delicious Cake", ImgDataStruct("Secrets/deliciouscake.bmp",0,255,0)},
{"Big Dipper", ImgDataStruct("Secrets/bigdipper.bmp",0,255,0)}
};

std::string Name(Secret s)
{
assert(s < NUMSECRETS);
return data[s].name;
}

ImgHandle Image(Secret s)
{
assert(s < NUMSECRETS);
return data[s].imgdata;
}
}[/source]
I trust exceptions about as far as I can throw them.

I like fastcall22's solution, except I wouldn't store the index as part of the object. Replacing a simple array with an std::map is a pessimization that I can't understand.

I think its mostly because any enum isn't guaranteed to be zero initialized (I'm sure there's a more technically correct term) or contiguous. While there isn't anything inherently wrong with fastcall's solution, the more general solution is something like a map.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
If enum values are really undefined, then there are bigger issues and using a different collection won't fix that.

The only case I can imagine where a map would be useful is if the enum values were discontinuous and had a large range, but that is specifically not the case here.
I trust exceptions about as far as I can throw them.
I agree that a map is overkill here. Using enums to index an array is perfectly fine.

If not specified the first enumerator has value zero. For the rest, if not specified the value of the enumerator is one more than the previous enumerator.

I think its mostly because any enum isn't guaranteed to be zero initialized (I'm sure there's a more technically correct term) or contiguous. While there isn't anything inherently wrong with fastcall's solution, the more general solution is something like a map.

In C++, enums are guaranteed to start at zero and count up one by one from there.

Without that guarantee, a lot of normal enum usages would break down.

enum PizzaToppings
{
Cheese, Pepperoni, Anchovies, ToppingsCount
};


ToppingsCount will be 3.

[quote name='alvaro' timestamp='1317692769' post='4868786']
I like fastcall22's solution, except I wouldn't store the index as part of the object. Replacing a simple array with an std::map is a pessimization that I can't understand.

I think its mostly because any enum isn't guaranteed to be zero initialized (I'm sure there's a more technically correct term) or contiguous. While there isn't anything inherently wrong with fastcall's solution, the more general solution is something like a map.
[/quote]

In C++ an enum is guaranteed to start at 0 and continue with 1, 2, 3, etc.

From the ANSI C++ standard (7.2 - Enumeration declarations [dcl.enum]):

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.[/quote]
I understand that. That's why I said there was nothing wrong with fastcall's code. I said you aren't guaranteed with any enum, meaning there exists at least one enum where it does not start at zero (i.e. if he set mushroom to 1000). Perhaps I could have chosen clearer words, because I can see now how you may have thought I meant you aren't guaranteed that with any enum at all. I was specifically referring to cases where the first enumerator has a non-zero initializer.

This is safe and well defined in this case. But there may come a time when you're using some external library, and you cant always assume the index will start at zero, because the library's author may have specified a different initialization. I just wanted the OP to be aware of that and know that if he is going to use an enum to index an array, he needs to know exactly how the enum was defined, or else he may end up with a big mess. Plus I was just responding to alvaro's comment, saying that there are indeed times when a map is both preferred and necessary.

Like I said, it is for this reason (and the fact that the programmer may have chosen non contiguous values) that maps are considered the "more general" solution. It does not, however, invalidate fastcall's solution in this case.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
I'm the one defining the enum. It's right there in the code. Of course I know what values it can take.
I trust exceptions about as far as I can throw them.
I know you do. I never said you didn't. But I don't know personally, and I don't know whether or not you would make this kind of assumption in the future, so I thought I would just add that and make it explicitly clear, just in case.

If you already do know everything I have stated, wonderful. Then I hope what I said will help someone who may browse these forums in the future and hopefully help them avoid making a poor assumption by helping them understand *why* its a poor assumption.

In this particular case, its safe, like I've said before. But its not safe in every possible case. You may already know that, but I have no way of knowing whether you do or not, nor do I know if any potential beginners browsing this thread know that or not. So I tried to add a small, clear comment as to why it isn't safe in every case.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

This topic is closed to new replies.

Advertisement