我应该对 c++ 中的非顺序常量使用枚举还是多个 const?
我正在编写将 file-io 函数集从 c 移植到 c++ 类中。 “幻数”(未命名常量)比比皆是。
这些函数读取一个文件头,其中包含许多特定条目,这些条目的位置当前由幻数表示。
几年前,一位资深程序员告诉我,使用“幻数”本质上是邪恶的,因此,从那以后我一直试图避免在我的端口中使用未命名常量。所以我想创建某种存储条目的常量列表。
到目前为止,我已经提出了两种看起来相对安全的解决方案——使用命名空间封闭的常量集或命名空间封闭的枚举。
我可以安全地使用任一解决方案吗?其中一种相对于另一种有什么优势吗?
例如
选项 1
namespace hdr_pos {
const unsigned int item_1_pos=4;
const unsigned int item_2_pos=8;
const unsigned int item_3_pos=12;
const unsigned int item_4_pos=24;
const unsigned int item_5_pos=32;
};
选项 2
namespace hdr_pos {
enum e {
item_1_pos=4,
item_2_pos=8,
item_3_pos=12,
item_4_pos=24,
item_5_pos=32
};
};
是否有办法防止重复,如果我由于将来更新文件头而更改位置,但忘记更改其中之一,是否可以捕获?
请保持事实和非主观性。如果您不知道有什么优势,请随意回答。
注意:当然,在我的实际实现中,我会使用更具描述性的名称;我只是将其称为 item_<#>_...作为示例...
I'm writing porting file-io set of functions from c into a c++ class. "Magic numbers" (unnamed constants) abound.
The functions read a file header which has a number of specific entries whose locations are currently denoted by magic numbers.
I was taught by a veteran programmer a couple years back that using "magic numbers" is inherently evil, and thus, I have since tried to avoid using unnamed constants in my port. So I want to create some sort of list of constants of where the entries are stored.
So far I've come up with two solutions that seem relatively safe -- use a namespace enclosed set of constants or a namespace enclosed enum.
Can I use either solution safely? Would there be any advantages to one over the other?
e.g.
OPTION 1
namespace hdr_pos {
const unsigned int item_1_pos=4;
const unsigned int item_2_pos=8;
const unsigned int item_3_pos=12;
const unsigned int item_4_pos=24;
const unsigned int item_5_pos=32;
};
OPTION 2
namespace hdr_pos {
enum e {
item_1_pos=4,
item_2_pos=8,
item_3_pos=12,
item_4_pos=24,
item_5_pos=32
};
};
Is there anyway to prevent duplicates, to catch if I change the positions due to a future update to the file header, but forget to change one of them?
Please keep this factual and non-subjective. If there is no advantage you know of, feel free to answer that.
Note: I would use more descriptive names, of course, in my actual implementation; I just called things item_<#>_... for examples sake...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果它们纯粹是常量并且不需要运行时的东西(比如不能用非枚举值初始化枚举)那么它们应该只是 const unsigned ints。当然,枚举的输入量较少,但这不是重点。
If they're purely constants and require no run-time stuff (like can't init enum with non-enum value) then they should just be const unsigned ints. Of course, the enum is less typing, but that's besides the point.
需要记住的一件事是,您不能获取
枚举
的地址:const unsigned* my_ Arbitary_item = &item_1_pos;
One thing to keep in mind is that you can't take the address of an
enum
:const unsigned* my_arbitrary_item = &item_1_pos;
您的问题标题表明您对使用枚举有疑问的主要原因是您的常量是非迭代的。但在 C++ 中,枚举类型已经是非迭代的。您必须跳过相当多的环节才能创建迭代枚举类型。
我想说,如果你的常量本质上是相关的,那么枚举是一个很好的主意,无论常量是否是迭代的。不过,枚举的主要缺点是完全缺乏类型控制。在许多情况下,您可能更愿意严格控制常量值的类型(例如让它们无符号),而这是 enum 无法帮助您的(至少目前如此)。
The title of your question suggests that the main reason you have doubts about using a enum is that your constants are non-iterative. But in C++ enum types are non-iterative already. You have to jump through quite a few hoops to make an iterative enum type.
I'd say that if your constants are related by nature, then enum is a pretty good idea, regardless of whether the constants are iterative or not. The main disadvantage of enums though is total lack of type control. In many cases you might prefer to have strict control over the types of your constant values (like have them unsigned) and that's something enum can't help you with (at least yet).
我以前也遇到过这种情况,有错误代码。
我见过人们使用枚举来表示错误代码,这会带来一些问题:
枚举
的各个字段在设计我的错误代码解决方案时,我因此选择了另一条路:命名空间中的常量,在源文件中定义,地址为 2 和 3。不过,为了获得类型安全性,常量不是
int
,而是特定的Code
类:然后我可以定义几个错误文件:
虽然我没有解决任意强制转换问题(构造函数是显式的,但是公共的),因为在我的例子中,我需要转发其他服务器返回的错误代码,而我当然没有想要了解所有这些(这太脆弱了)
但是我确实考虑过,通过将所需的构造函数设为私有并强制使用构建器,我们甚至可以在swoop:
更多的工作(对于框架),并且仅对相同的分配检查进行链接时/运行时检查。尽管只需扫描模式
MAKE_NEW_ERROR_CODE
即可轻松诊断重复项,但祝您玩得开心!
I've dealt with this situation before, for error codes.
I have seen people using enums for error codes, and this pose some issues:
enum
When designing my error codes solution, I thus chose another road: constants in a namespace, defined in source files, which address points 2 and 3. To gain in type safety though, the constants are not
int
, but a specificCode
class:Then I can define several error files:
I didn't solved the arbitrary cast issue though (constructor is explicit, but public), because in my case I was required to forward error codes returned by other servers, and I certainly didn't want to have to know them all (that would have been too brittle)
However I did thought about it, by making the required constructor private and enforcing the use of a builder, we're even going to get 4. and 5. in a swoop:
A tad more work (for the framework), and only link-time/run-time check of the same assignment check. Though it's easy to diagnose duplicates simply by scanning for the pattern
MAKE_NEW_ERROR_CODE
Have fun!
我可以看到使用枚举的两个优点。首先,一些调试器可以将常量转换回枚举变量名称(这在某些情况下可以使调试更容易)。此外,您还可以声明一个枚举类型的变量,该变量只能保存该枚举中的值。这可以为您提供另一种形式的类型检查,而仅通过使用常量是无法做到这一点的。
检查值是否重复可能取决于您的特定编译器。最简单的方法可能是编写一个外部脚本,该脚本将解析您的枚举定义并报告值是否重复(如果您愿意,可以将其作为构建过程的一部分运行)。
I can see two advantages to using an enum. First, some debuggers can translate constants back into enum variable names (which can make debugging easier in some cases). Also, you can declare a variable of an enumerated type which can only hold a value from that enumeration. This can give you an additional form of type checking that you wouldn't have simply by using constants.
Checking to see if a value is duplicated might depend on your particular compiler. The easiest way to do so would probably be to write an external script that will parse your enum definition and report whether or not a value is duplicated (you can run this as part of your build process if you like).