gpt4 book ai didi

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

转载 作者:IT老高 更新时间:2023-10-28 11:34:25 31 4
gpt4 key购买 nike

在我正在处理的 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/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com