我应该使用的#define,枚举或const? [英] Should I use #define, enum or const?
问题描述
在一个C ++项目我的工作,我有一个的标记的一种价值,可以有四个值。这四个标志可以结合起来。标志描述数据库中的记录,可以是:
In a C++ project I'm working on, I have a flag kind of value which can have four values. Those four flags can be combined. Flags describe the records in database and can be:
- 新纪录
- 删除的记录
- 修改的记录
- 现有记录
现在,每个记录我想保留这个属性,所以我可以使用一个枚举:
Now, for each record I wish to keep this attribute, so I could use an enum:
enum { xNew, xDeleted, xModified, xExisting }
然而,在code其他地方,我需要选择哪些记录是可见的用户,所以我希望能够通过,作为一个单一的参数,如:
However, in other places in code, I need to select which records are to be visible to the user, so I'd like to be able to pass that as a single parameter, like:
showRecords(xNew | xDeleted);
所以,看来我有三个可能的appoaches:
So, it seems I have three possible appoaches:
#define X_NEW 0x01
#define X_DELETED 0x02
#define X_MODIFIED 0x04
#define X_EXISTING 0x08
或
typedef enum { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } RecordType;
或
namespace RecordType {
static const uint8 xNew = 1;
static const uint8 xDeleted = 2;
static const uint8 xModified = 4;
static const uint8 xExisting = 8;
}
空间要求是很重要的(字节VS INT),但并不重要。随着定义我失去的类型安全,并与枚举
我失去了一些空间(整数),并可能要投的时候我想做一个按位运算。随着常量
我想我也失去类型安全因为随机 UINT8
可能错误地进入。
Space requirements are important (byte vs int) but not crucial. With defines I lose type safety, and with enum
I lose some space (integers) and probably have to cast when I want to do a bitwise operation. With const
I think I also lose type safety since a random uint8
could get in by mistake.
有一些其他清洁的方式?
Is there some other cleaner way?
如果没有,你会怎么用,为什么?
If not, what would you use and why?
P.S。在code的其余部分是相当清洁的现代C ++没有的#define
s,而我在几个空格使用的命名空间和模板,所以这些都不是不成问题无论是。
P.S. The rest of the code is rather clean modern C++ without #define
s, and I have used namespaces and templates in few spaces, so those aren't out of question either.
推荐答案
联合的战略,以减少单一方法的缺点。我在嵌入式系统工作,所以下面解决方案是基于这样的事实,整数和位运算符的速度快,低存储器放大器;低使用闪光灯。
Combine the strategies to reduce the disadvantages of a single approach. I work in embedded systems so the following solution is based on the fact that integer and bitwise operators are fast, low memory & low in flash usage.
将枚举在命名空间prevent,防止污染全局命名空间的常量。
Place the enum in a namespace to prevent the constants from polluting the global namespace.
namespace RecordType {
这是枚举声明和定义一个编译期进行检查类型。始终使用编译时类型检查,以确保参数和变量给出正确的类型。有没有必要在C ++中的typedef。
An enum declares and defines a compile time checked typed. Always use compile time type checking to make sure arguments and variables are given the correct type. There is no need for the typedef in C++.
enum TRecordType { xNew = 1, xDeleted = 2, xModified = 4, xExisting = 8,
创建一个无效的状态,另一名成员。这可能是因为错误code有用的;例如,当您想要返回的状态,但在I / O操作失败。这也是对调试很有;用它在初始化列表和析构函数知道是否应该使用的变量的值。
Create another member for an invalid state. This can be useful as error code; for example, when you want to return the state but the I/O operation fails. It is also useful for debugging; use it in initialisation lists and destructors to know if the variable's value should be used.
xInvalid = 16 };
考虑您有两个目的为这种类型。要跟踪记录的当前状态,并创建一个面具来选择某些国家的记录。创建一个内联函数测试类型的值是否有效你的目的;作为国家标志VS的状态面具。这将捉虫子的的typedef
只是一个 INT
和值,如 0xDEADBEEF
可能是您的变量未初始化通过或mispointed变量。
Consider that you have two purposes for this type. To track the current state of a record and to create a mask to select records in certain states. Create an inline function to test if the value of the type is valid for your purpose; as a state marker vs a state mask. This will catch bugs as the typedef
is just an int
and a value such as 0xDEADBEEF
may be in your variable through uninitialised or mispointed variables.
inline bool IsValidState( TRecordType v) {
switch(v) { case xNew: case xDeleted: case xModified: case xExisting: return true; }
return false;
}
inline bool IsValidMask( TRecordType v) {
return v >= xNew && v < xInvalid ;
}
如果你想经常使用的类型添加使用
指令。
Add a using
directive if you want to use the type often.
using RecordType ::TRecordType ;
值检测功能是有用,一旦它们被用来断言捕获错误值。运行时,它可以做的损伤少越快你赶上一个错误。
The value checking functions are useful in asserts to trap bad values as soon as they are used. The quicker you catch a bug when running, the less damage it can do.
下面是一些例子,把它放在一起。
Here are some examples to put it all together.
void showRecords(TRecordType mask) {
assert(RecordType::IsValidMask(mask));
// do stuff;
}
void wombleRecord(TRecord rec, TRecordType state) {
assert(RecordType::IsValidState(state));
if (RecordType ::xNew) {
// ...
} in runtime
TRecordType updateRecord(TRecord rec, TRecordType newstate) {
assert(RecordType::IsValidState(newstate));
//...
if (! access_was_successful) return RecordType ::xInvalid;
return newstate;
}
,以确保正确的值安全的唯一方法是使用带运算符重载专用类和留作练习另一位读者。
The only way to ensure correct value safety is to use a dedicated class with operator overloads and that is left as an exercise for another reader.
这篇关于我应该使用的#define,枚举或const?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!