匿名enum
声明的目的是什么,例如:
enum { color = 1 };
为什么不只是声明int color = 1
?
匿名enum
声明的目的是什么,例如:
enum { color = 1 };
为什么不只是声明int color = 1
?
foo = color;
->mov 1, foo
color
为1
。就像数字42不会占用程序中的内存一样,枚举也不会。顺便说一句,该死的你让我弄错了颜色:)
Answers:
枚举不占用任何空间并且是不可变的。
如果您使用过,const int color = 1;
则可以解决可变性问题,但是如果有人使用color
(const int* p = &color;
)的地址,则必须为其分配空间。这可能没什么大不了的,但是除非您明确希望人们能够使用color
您的住址,否则最好不要这样做。
同样,当在类中声明一个常量字段时,它必须是常量static const
(对于现代C ++而言并非如此),并且并非所有编译器都支持静态const成员的内联初始化。
免责声明:不应将此答案作为建议enum
用于所有数字常量。您应该做您(或您的同事)认为更具可读性的事情。答案仅列出了一些您可能更喜欢使用的原因enum
。
const int
是不可变的,并且可能不会占用任何空间,具体取决于编译器选择执行的操作。
enum
在运行时更改!
如果这是旧代码,则可能已将枚举用于“枚举破解”。
您可以在以下链接中了解有关“枚举黑客”的更多信息:枚举黑客
一种用途是在进行模板元编程时,因为枚举对象不是左值,而static const
成员是左值。对于过去不允许您在类定义中初始化静态整数常量的编译器,它也是一种常见的解决方法。这在另一个问题中得到解释。
constexpr
。
(1) int color = 1;
color
是可变的(偶然)。
(2) enum { color = 1 };
color
无法更改。
另一个选择enum
是
const int color = 1; // 'color' is unmutable
双方enum
并const int
提供完全相同的概念; 这是一个选择问题。关于enum
节省空间的流行观点,IMO没有与此相关的内存限制,编译器足够聪明,可以const int
在需要时进行优化。
[注意:如果有人试图使用const_cast<>
上const int
; 它将导致不确定的行为(这是不好的)。但是,对于则不可能enum
。所以,我个人最喜欢的是enum
]
const int
应该首选,因为语义与意图更紧密匹配(这不是枚举!)。
const int color = 1;
如果您确实愿意,可以使用更改颜色const_cast
;枚举,但是,不能更改。
const_cast
保持constness :这是未定义的行为。
enum
了const int
; 国际海事组织,他们更有组织,不太可能受到const_cast
UB的伤害和结果。
当您使用时,
enum {color = 1}
您不会使用任何内存,就像
#define color 1
如果声明一个变量,
int color=1
那么您将占用不可变的值的内存。
const int x=1; const int* y=&x; cout << y;
。声明后,没有任何内容写入x。您可能想查看此结果。
可读性和性能。
详细信息描述为以下示例的注释。
在虚幻引擎4(C ++游戏引擎)中,我具有以下属性(引擎暴露的成员变量):
/// Floor Slope.
UPROPERTY
(
Category = "Movement",
VisibleInstanceOnly,
BlueprintGetter = "BP_GetFloorSlope",
BlueprintReadOnly,
meta =
(
ConsoleVariable = "Movement.FloorSlope",
DisplayName = "Floor Slope",
ExposeOnSpawn = true,
NoAutoLoad
)
)
float FloorSlope = -1.f;
这是玩家所站的地面坡度值(值∈[0; 90)°)(如果有)。
由于引擎的限制,它既不能也不std::optional
是TOptional
。
我想出了一个解决方案,以添加另一个可自我解释的变量bIsOnFloor
。
bool bIsOnFloor = false;
我的仅限C ++内部设置器FloorSlope
采用以下形式:
void UMovement::SetFloorSlope(const float& FloorSlope) noexcept
contract [[expects audit: FloorSlope >= 0._deg && FloorSlope < 90._deg]]
{
this->bIsOnFloor = true;
this->FloorSlope = FloorSlope;
AUI::UI->Debug->FloorSlope = FString::Printf(L"Floor Slope: %2.0f", FloorSlope);
};
在FloorSlope
参数将作为参数的情况下添加特殊情况-1.f
将很难猜测,而且也不友好。相反,我宁愿创建False
enum
字段:
enum { False };
这样,我可以简单地重载SetFloorSlope
需要直观的功能False
而不是-1.f
。
void UMovement::SetFloorSlope([[maybe_unused]] const decltype(False)&) noexcept
{
this->bIsOnFloor = false;
this->FloorSlope = -1.f;
AUI::UI->Debug->FloorSlope = L"Floor Slope: —";
};
当玩家角色在对勾施加重力时撞到地板时,我简单地称呼:
SetFloorSlope(FloorSlope);
...其中FloorSlope
是一个float
值∈[0; 90)°。否则(如果它没有跌落),我打电话给:
SetFloorSlope(False);
这种形式(与通过 -1.f
)更具可读性,并且易于解释。
另一个示例可能是阻止或强制初始化。以上提到的虚幻引擎4常用FHitResult
struct
包含有关轨迹的一次命中的信息,例如撞击点和该点的表面法线。
默认情况下,此复杂struct
调用Init
方法为某些成员变量设置一些值。这可以被强制或阻止(公共文档:FHitResult
#constructor):
FHitResult()
{
Init();
}
explicit FHitResult(float InTime)
{
Init();
Time = InTime;
}
explicit FHitResult(EForceInit InInit)
{
Init();
}
explicit FHitResult(ENoInit NoInit)
{
}
Epic Games定义了enum
类似的enum
名称,但添加了多余的名称:
enum EForceInit
{
ForceInit,
ForceInitToZero
};
enum ENoInit {NoInit};
传递NoInit
给FHitResult
prevent初始化的构造函数,这可以通过不初始化将在其他地方初始化的值来提高性能。
FHitResult(NoInit)
DamirH在“综合游戏能力分析系列”中的帖子中的用法:
//A struct for temporary holding of actors (and transforms) of actors that we hit
//that don't have an ASC. Used for environment impact GameplayCues.
struct FNonAbilityTarget
{
FGameplayTagContainer CueContainer;
TWeakObjectPtr<AActor> TargetActor;
FHitResult TargetHitResult;
bool bHasHitResult;
public:
FNonAbilityTarget()
: CueContainer(FGameplayTagContainer())
, TargetActor(nullptr)
, TargetHitResult(FHitResult(ENoInit::NoInit))
, bHasHitResult(false)
{
}
// (…)