c++ - 我应该使用#define、枚举还是常量?

标签 c++ enums bit-manipulation c-preprocessor

在我正在处理的 C++ 项目中,我有一个 flag 类型的值,它可以有四个值。这四个标志可以组合。标志描述数据库中的记录,可以是:

  • 新纪录
  • 已删除记录
  • 修改记录
  • 现有记录

现在,对于每条记录,我希望保留此属性,因此我可以使用枚举:

enum { xNew, xDeleted, xModified, xExisting }

但是,在代码的其他地方,我需要选择哪些记录对用户可见,所以我希望能够将其作为单个参数传递,例如:

showRecords(xNew | xDeleted);

所以,我似乎有三种可能的方法:

#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;
}

空间要求很重要(字节与整数),但并不重要。使用定义我失去了类型安全性,使用 enum 我失去了一些空间(整数),并且当我想要进行按位运算时可能不得不强制转换。使用 const 我想我也会失去类型安全性,因为随机的 uint8 可能会误入。

还有其他更干净的方法吗?

如果没有,你会用什么?为什么?

附:其余的代码是相当干净的现代 C++,没有 #defines,而且我在少数空间中使用了命名空间和模板,所以这些也不是没有问题的。

最佳答案

结合策略以减少单一方法的缺点。我在嵌入式系统中工作,因此以下解决方案基于整数和位运算符速度快、内存低且闪存使用率低这一事实。

将枚举放在命名空间中,以防止常量污染全局命名空间。

namespace RecordType {

枚举声明并定义了一个编译时检查类型。始终使用编译时类型检查来确保参数和变量的类型正确。 C++ 中不需要 typedef。

enum TRecordType { xNew = 1, xDeleted = 2, xModified = 4, xExisting = 8,

为无效状态创建另一个成员。这可以用作错误代码;例如,当您想要返回状态但 I/O 操作失败时。它对调试也很有用;在初始化列表和析构函数中使用它来了解是否应该使用变量的值。

xInvalid = 16 };

考虑到这种类型有两个目的。跟踪记录的当前状态并创建掩码以选择处于某些状态的记录。创建一个内联函数来测试该类型的值是否对您的目的有效;作为状态标记与状态掩码。这将捕获错误,因为 typedef 只是一个 int 并且诸如 0xDEADBEEF 之类的值可能通过未初始化或错误指向的变量存在于您的变量中。

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 ;
}

如果您想经常使用该类型,请添加 using 指令。

using RecordType ::TRecordType ;

值检查函数在断言中很有用,可以在使用错误值时立即捕获它们。跑的时候越快抓到 bug ,它造成的伤害就越小。

这里有一些例子可以把它们放在一起。

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;
}

确保正确值安全的唯一方法是使用具有运算符重载的专用类,这留给其他读者作为练习。

关于c++ - 我应该使用#define、枚举还是常量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/112433/

相关文章:

java - 使用 values( ) 创建枚举常量的最终 Java 类数组

c++ - 对于函数 : constexpr const or enum? 中的常量,我应该更喜欢哪个

angular - 如何在 Angular 4 的下拉菜单中正确绑定(bind)枚举?

c - Keccak 中的舍入常量

c++ - xvalue 上的下标表达式的值类别

c++ - 如何避免重复声明 Q_DECLARE_METATYPE<aCommonType>

c++ - std::async - 依赖于实现的用法?

c++ - Raymond Chen 的单例实现使用狡猾的转换?

javascript - 如何在 JavaScript 中模拟 64 位(无符号)整数的按位旋转?

java - 将按位运算Java代码转换为PHP