What is the purpose of anonymous enum declarations such as:
enum { color = 1 };
Why not just declare int color = 1?
That's a so-called enum trick for declaring a compile-time integer constant. It's advantage is it guarantees that no variable is instantiated and therefore there's no runtime overhead. Most compilers introduce no overhead with integer constants anyway.
Enums don't take up any space and are immutable.
If you used const int color = 1; then you would solve the mutability issue but if someone took the address of color (const int* p = &color;) then space for it would have to be allocated. This may not be a big deal but unless you explicitly want people to be able to take the address of color you might as well prevent it.
Also when declaring a constant field in a class then it will have to be static const (not true for modern C++) and not all compilers support inline initialization of static const members.
Disclaimer: This answer should not be taken as advice to use enum for all numeric constants. You should do what you (or your co-workers) think is more readable. The answer just lists some reasons one might prefer to use an enum.
If this is old code, then enum might have been used for the "enum hack".
You can learn more about the "enum hack", for example, in this link: enum hack
In short: this allows defining the value once, just like #define or defining a variable, but unlike #define - here the compiler makes sure that the value is a number (int, r-value) and prevents you from doing all kinds of mischief that you can do with the precompiler's simple "search and replace", and unlike defining a variable - never takes up space under any compiler or configuration, and prevents changes to it (even const variables can sometimes be changed if you try hard enough).
(1) int color = 1;
color is changeable (accidently).
(2) enum { color = 1 };
color cannot be changed.
The other option for enum is,
const int color = 1; // 'color' is unmutable
Both enum and const int offer exactly same concept; it's a matter of choice. With regards to popular belief that enums save space, IMO there is no memory constraint related to that, compiler are smart enough to optimize const int when needed.
[Note: If someone tries to use const_cast<> on a const int; it will result in undefined behavior (which is bad). However, the same is not possible for enum. So my personal favorite is enum]
One use of this is when you're doing template metaprogramming, because enum objects are not lvalues, while static const members are. It also used to be a common workaround for compilers that didn't let you initialize static integral constants in the class definition. This is explained in another question.
When you use
enum {color = 1}
you're not using any memory it's like
#define color 1
If you declare a variable
int color=1
Then you're taking up memory for a value that's not to be changed.
Answer
Readability and performance.
Details are describbed as notes to examples below.
Use cases
Personal example
In Unreal Engine 4 (C++ game engine), I have following property (engine exposed member variable):
/// Floor Slope.
UPROPERTY
(
Category = "Movement",
VisibleInstanceOnly,
BlueprintGetter = "BP_GetFloorSlope",
BlueprintReadOnly,
meta =
(
ConsoleVariable = "Movement.FloorSlope",
DisplayName = "Floor Slope",
ExposeOnSpawn = true,
NoAutoLoad
)
)
float FloorSlope = -1.f;
This is a value of floor slope player is standing on (value ∈ [0; 90)°), if any.
Because of engine limitations, it cannot be neither std::optional nor TOptional.
I've came up with a solution to add another self explainable variable bIsOnFloor.
bool bIsOnFloor = false;
My C++ only internal setter for FloorSlope takes the following form:
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);
};
Adding special case where FloorSlope parameter would take argument of -1.f would be hard to guess and not user friendly.
Instead, I'd rather create False enum field:
enum { False };
This way, I can simply overload SetFloorSlope function that takes intuitive False instead of -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: —";
};
When a player character hits a floor upon applying gravity to it on tick, I simply call:
SetFloorSlope(FloorSlope);
… where FloorSlope is a float value ∈ [0; 90)°.
Otherwise (if it does not hits a floor), I call:
SetFloorSlope(False);
This form (as opposed to passing -1.f) is much more readable, and self explanatory.
Engine example
Another example may be to prevent or force initialization.
Mentioned above Unreal Engine 4 commonly uses FHitResult struct containing information about one hit of a trace, such as point of impact and surface normal at that point.
This complex struct calls Init method by default, setting some values to certain member variables. This can be forced or prevented (public docs: FHitResult #constructor):
FHitResult()
{
Init();
}
explicit FHitResult(float InTime)
{
Init();
Time = InTime;
}
explicit FHitResult(EForceInit InInit)
{
Init();
}
explicit FHitResult(ENoInit NoInit)
{
}
Epic Games defines such enums similiar, but adds redundant enum names:
enum EForceInit
{
ForceInit,
ForceInitToZero
};
enum ENoInit {NoInit};
Passing NoInit to the constructor of FHitResult prevents initialization, what can lead to performance gain by not initializing values that will be initialized elsewhere.
Community example
FHitResult(NoInit) usage in DamirH's post on Comprehensive GameplayAbilities Analysis Series:
//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)
{
}
// (…)
I dont see it mentioned, another use is to scope your constants. I currently work on code that was written using Visual Studio 2005, and it is now ported to android - g++. In VS2005 you could have code like this enum MyOpts { OPT1 = 1 }; and use it as MyOpts::OPT1 - and compiler did not complain about it, even though it is not valid. g++ reports such code as error, so one solution is to use anonymous enum as follows: struct MyOpts { enum {OPT1 =1}; };, and now both compilers are happy.
Related
Sometimes I wanna use globals but instead of it I use local variables. Let we have some Font class:
class Font {
public:
class Alignment {
public:
unsigned short currentAlignment;
unsigned short FONT_ALIGN_LEFT = 0;
unsigned short FONT_ALIGN_CENTER = 1;
unsigned short FONT_ALIGN_RIGHT = 2;
// etc....
};
Alignment alignment;
void setFontAlignment( unsigned short fontAlignment ) {
this->alignment.currentAlignment = fontAlignment;
}
};
To use this class we need to do something like that:
Font font;
font.setFontAlignment( font.alignment.FONT_ALIGN_CENTER );
// if we need to check currentAlignment we need to do:
if ( font.alignment.currentAlignment == font.alignment.FONT_ALIGN_CENTER ) {...} // looks a little bit awful :)
Or we have another approach to do this:
= Font.h =
#define FONT_ALIGN_LEFT 0
#define FONT_ALIGN_CENTER 1
#define FONT_ALIGN_RIGHT 2
// etc....
class Font {
public:
unsigned short currentAlignment;
void setFontAlignment( unsigned short fontAlignment ) {
this->currentAlignment = fontAlignment;
}
}
To use this:
#include "Font.h"
...
Font font;
font.setFontAlignment( FONT_ALIGN_CENTER );
if ( font.currentAlignment == FONT_ALIGN_CENTER ) {...} // looks a little bit better :)
Which one is better for memory optimizing and why? Which one do you prefer to use? Or maybe you know some better solutions?
Although there are always exceptions, I usually go by (among others :-) the following guidelines:
Avoid globals as much as possible. Confine to smallest applicable
scope (within reason).
Avoid second guessing the compiler, except for grossly obvious
situations.
Actually, a combination of them. But let's clarify something. You don't speak about any global variable in your question. A global variable is a variable defined in the global scope.
The primary reason of using object oriented programming is not its efficiency (as it is slower than purely procedural code), but its ability to model the world. So, when creating an oop design, you shouldn't care too much about the resourced (time, memory), but how good it models the world.
The second version is bad, because it introduces a lot of constants in the global scope, and you want to avoid that. Also, it does a very bad job at encapsulating the data (the user of your Font class shouldn't care about the values of the alignment).
The first version is better, but there are some problems. First, you need to think about the objects you should have? Do you actually need an Alignment object? You may need it, but in this particular example, I don't see why. So, you could make it model the world as it is, without introducing some artificial elements:
class Font {
public:
unsigned short currentAlignment;
void alignLeft() {
this->currentAlignment = 0;
}
void alignCenter() {
this->currentAlignment = 1;
}
void alignRight() {
this->currentAlignment = 2;
}
};
Now it is very easy to use. I don't have to keep in my global scope unnecessary constants. Now, the problem is what happens when the user reads the value of the currentAlignment? Of course, you don't want to use the constants, but you don't need to. It really depends on the world you're modelling. As this is a Font class, it should be the only one who really cares about the value of the alignment. If somebody else needs the value, you could have some methods like isCenter() that return true when the font is center-aligned. But also, I would consider making the currentAlignment private.
What is the purpose of anonymous enum declarations such as:
enum { color = 1 };
Why not just declare int color = 1?
That's a so-called enum trick for declaring a compile-time integer constant. It's advantage is it guarantees that no variable is instantiated and therefore there's no runtime overhead. Most compilers introduce no overhead with integer constants anyway.
Enums don't take up any space and are immutable.
If you used const int color = 1; then you would solve the mutability issue but if someone took the address of color (const int* p = &color;) then space for it would have to be allocated. This may not be a big deal but unless you explicitly want people to be able to take the address of color you might as well prevent it.
Also when declaring a constant field in a class then it will have to be static const (not true for modern C++) and not all compilers support inline initialization of static const members.
Disclaimer: This answer should not be taken as advice to use enum for all numeric constants. You should do what you (or your co-workers) think is more readable. The answer just lists some reasons one might prefer to use an enum.
If this is old code, then enum might have been used for the "enum hack".
You can learn more about the "enum hack", for example, in this link: enum hack
In short: this allows defining the value once, just like #define or defining a variable, but unlike #define - here the compiler makes sure that the value is a number (int, r-value) and prevents you from doing all kinds of mischief that you can do with the precompiler's simple "search and replace", and unlike defining a variable - never takes up space under any compiler or configuration, and prevents changes to it (even const variables can sometimes be changed if you try hard enough).
(1) int color = 1;
color is changeable (accidently).
(2) enum { color = 1 };
color cannot be changed.
The other option for enum is,
const int color = 1; // 'color' is unmutable
Both enum and const int offer exactly same concept; it's a matter of choice. With regards to popular belief that enums save space, IMO there is no memory constraint related to that, compiler are smart enough to optimize const int when needed.
[Note: If someone tries to use const_cast<> on a const int; it will result in undefined behavior (which is bad). However, the same is not possible for enum. So my personal favorite is enum]
One use of this is when you're doing template metaprogramming, because enum objects are not lvalues, while static const members are. It also used to be a common workaround for compilers that didn't let you initialize static integral constants in the class definition. This is explained in another question.
When you use
enum {color = 1}
you're not using any memory it's like
#define color 1
If you declare a variable
int color=1
Then you're taking up memory for a value that's not to be changed.
Answer
Readability and performance.
Details are describbed as notes to examples below.
Use cases
Personal example
In Unreal Engine 4 (C++ game engine), I have following property (engine exposed member variable):
/// Floor Slope.
UPROPERTY
(
Category = "Movement",
VisibleInstanceOnly,
BlueprintGetter = "BP_GetFloorSlope",
BlueprintReadOnly,
meta =
(
ConsoleVariable = "Movement.FloorSlope",
DisplayName = "Floor Slope",
ExposeOnSpawn = true,
NoAutoLoad
)
)
float FloorSlope = -1.f;
This is a value of floor slope player is standing on (value ∈ [0; 90)°), if any.
Because of engine limitations, it cannot be neither std::optional nor TOptional.
I've came up with a solution to add another self explainable variable bIsOnFloor.
bool bIsOnFloor = false;
My C++ only internal setter for FloorSlope takes the following form:
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);
};
Adding special case where FloorSlope parameter would take argument of -1.f would be hard to guess and not user friendly.
Instead, I'd rather create False enum field:
enum { False };
This way, I can simply overload SetFloorSlope function that takes intuitive False instead of -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: —";
};
When a player character hits a floor upon applying gravity to it on tick, I simply call:
SetFloorSlope(FloorSlope);
… where FloorSlope is a float value ∈ [0; 90)°.
Otherwise (if it does not hits a floor), I call:
SetFloorSlope(False);
This form (as opposed to passing -1.f) is much more readable, and self explanatory.
Engine example
Another example may be to prevent or force initialization.
Mentioned above Unreal Engine 4 commonly uses FHitResult struct containing information about one hit of a trace, such as point of impact and surface normal at that point.
This complex struct calls Init method by default, setting some values to certain member variables. This can be forced or prevented (public docs: FHitResult #constructor):
FHitResult()
{
Init();
}
explicit FHitResult(float InTime)
{
Init();
Time = InTime;
}
explicit FHitResult(EForceInit InInit)
{
Init();
}
explicit FHitResult(ENoInit NoInit)
{
}
Epic Games defines such enums similiar, but adds redundant enum names:
enum EForceInit
{
ForceInit,
ForceInitToZero
};
enum ENoInit {NoInit};
Passing NoInit to the constructor of FHitResult prevents initialization, what can lead to performance gain by not initializing values that will be initialized elsewhere.
Community example
FHitResult(NoInit) usage in DamirH's post on Comprehensive GameplayAbilities Analysis Series:
//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)
{
}
// (…)
I dont see it mentioned, another use is to scope your constants. I currently work on code that was written using Visual Studio 2005, and it is now ported to android - g++. In VS2005 you could have code like this enum MyOpts { OPT1 = 1 }; and use it as MyOpts::OPT1 - and compiler did not complain about it, even though it is not valid. g++ reports such code as error, so one solution is to use anonymous enum as follows: struct MyOpts { enum {OPT1 =1}; };, and now both compilers are happy.
Perhaps something similar has already been asked, and sure, it's a nitpick...
I have a bunch of constant std::maps to switch between enum (class) values and their std::string representations (both ways). Someone here pointed out to me that these maps will be initialized at runtime, when other initialization code is run, before my program executes all the good stuff. This would mean constant expressions would impact runtime performance, as the maps are built up from their enum-string pairs.
As an illustrative example, here is an example of one of these maps:
enum class os
{
Windows,
Linux,
MacOSX
};
const map<string, os> os_map =
{ {"windows", os::Windows},
{"linux", os::Linux},
{"mac", os::MacOSX} };
const map<os, string> os_map_inverse =
{ {os::Windows, "windows"},
{os::Linux, "linux"},
{os::MacOSX, "mac"} };
Would the C++11 constexpr have any influence on performance, or is my assumption of a runtime initialization penalty false? I would think a compiler can embed a constant STL container as pure data in the executable, but apparently that may not be as easy as I make it sound?
It's not so much the performance of initialization that is a problem, but the order of initialization. If someone uses your map before main has started (for example at initialization for a namespace scope variable), then you are SOL, because you are not guaranteed that your map has been initialized before the user's initialization uses it.
However you can do this thing at compile time. String literals are constant expressions, as are enumerators. A simple linear-time complexity structure
struct entry {
char const *name;
os value;
};
constexpr entry map[] = {
{ "windows", os::Windows },
{ "linux", os::Linux },
{ "mac", os::Mac }
};
constexpr bool same(char const *x, char const *y) {
return !*x && !*y ? true : (*x == *y && same(x+1, y+1));
}
constexpr os value(char const *name, entry const *entries) {
return same(entries->name, name) ? entries->value : value(name, entries+1);
}
If you use value(a, b) in a constant expression context, and the name you specify doesn't exist, you will get a compile time error because the function call would become non-constant.
To use value(a, b) in a non-constant expression context, you better add safety features, like adding an end marker to your array and throwing an exception in value if you hit the end marker (the function call will still be a constant expression as long as you never hit the end marker).
constexpr does not work on arbitrary expressions, and especially not on things that will use the freestore. map/string will use the freestore, and thus constexpr will not work for initializing them at compile time, and have no code run at runtime.
As for the runtime penalty: Depending on the storage duration of those variables (and I assume static here, which means initialization before main), you will not even be able to measure the penalty, especially not in the code that is using them, assuming you will use them many times, where the lookup has much more "overhead" than the initialization.
But as for everything, remember rule one: Make things work. Profile. Make things fast. In this order.
Ah yes, it's a typical issue.
The only alternative I've found to avoid this runtime initialization is to use plain C structures. If you're willing to go the extra-mile and store the values in a plain C array, you can get static initialization (and reduced memory footprint).
It's one of the reason LLVM/Clang actually use the tblgen utility: plain tables are statically initialized, and you can generate them sorted.
Another solution would be to create a dedicated function instead: for the enum to string conversion it's easy to use a switch and let the compiler optimize it into a plain table, for the string to enum it's a bit more involved (you need if/else branches organized right to get the O(log N) behavior) but for small enums a linear search is as good anyway, in which case a single macro hackery (based off Boost Preprocessor goodness) can get you everything you need.
I have recently found my own best way to furnish an enum. See the code:
enum State {
INIT, OK, ENoFou, EWroTy, EWroVa
};
struct StateToString {
State state;
const char *name;
const char *description;
public:
constexpr StateToString(State const& st)
: state(st)
, name("Unknown")
, description("Unknown")
{
switch(st){
case INIT : name = "INIT" , description="INIT"; break;
case OK : name = "OK" , description="OK"; break;
case ENoFou: name = "ENoFou", description="Error: Not found"; break;
case EWroTy: name = "EWroTy", description="Error: Wrong type"; break;
case EWroVa: name = "EWroVa", description="Error: Wrong value, setter rejected"; break;
// Do not use default to receive a comile-time warning about not all values of enumeration are handled. Need `-Wswitch-enum` in GCC
}
}
};
Extending this example to some universal code, let's name it lib code:
/// Concept of Compile time meta information about (enum) value.
/// This is the best implementation because:
/// - compile-time resolvable using `constexpr name = CtMetaInfo<T>(value)`
/// - enum type can be implemented anywhere
/// - compile-time check for errors, no hidden run-time surprises allowed - guarantied by design.
/// - with GCC's `-Wswitch` or `-Werror=switch` - you will never forget to handle every enumerated value
/// - nice and simple syntaxis `CtMetaInfo(enumValue).name`
/// - designed for enums suitable for everything
/// - no dependencies
/// Recommendations:
/// - write `using TypeToString = CtMetaInfo<Type>;` to simplify code reading
/// - always check constexpr functions assigning their return results to constexpr values
/**\code
template< typename T >
concept CtMetaInfo_CONCEPT {
T value;
const char *name;
// Here could add variables for any other meta information. All vars must be filled either by default values or in ctor init list
public:
///\param defaultName will be stored to `name` if constructor body will not reassign it
constexpr CtMetaInfoBase( T const& val, const char* defaultName="Unknown" );
};
\endcode
*/
/// Pre-declare struct template. Specializations must be defined.
template< typename T >
struct CtMetaInfo;
/// Template specialization gives flexibility, i.e. to define such function templates
template <typename T>
constexpr const char* GetNameOfValue(T const& ty)
{ return CtMetaInfo<T>(ty).name; }
User must define specialization for user's type:
/// Specialization for `rapidjson::Type`
template<>
struct CtMetaInfo<Type> {
using T = Type;
T value;
const char *name;
public:
constexpr CtMetaInfo(T const& val)
: value(val)
, name("Unknown")
{
switch(val){
case kNullType : name = "Null" ; break;
case kFalseType: case kTrueType: name = "Bool" ; break;
case kObjectType : name = "Object"; break;
case kArrayType : name = "Array" ; break;
case kStringType : name = "String"; break;
case kNumberType : name = "Number"; break;
}
}
static constexpr const char* Name(T const& val){
return CtMetaInfo<Type>(val).name;
}
};
/// TEST
constexpr const char *test_constexprvalue = CtMetaInfo<Type>(kStringType).name;
constexpr const char *test_constexprvalu2 = GetNameOfValue(kNullType);
What is the purpose of anonymous enum declarations such as:
enum { color = 1 };
Why not just declare int color = 1?
That's a so-called enum trick for declaring a compile-time integer constant. It's advantage is it guarantees that no variable is instantiated and therefore there's no runtime overhead. Most compilers introduce no overhead with integer constants anyway.
Enums don't take up any space and are immutable.
If you used const int color = 1; then you would solve the mutability issue but if someone took the address of color (const int* p = &color;) then space for it would have to be allocated. This may not be a big deal but unless you explicitly want people to be able to take the address of color you might as well prevent it.
Also when declaring a constant field in a class then it will have to be static const (not true for modern C++) and not all compilers support inline initialization of static const members.
Disclaimer: This answer should not be taken as advice to use enum for all numeric constants. You should do what you (or your co-workers) think is more readable. The answer just lists some reasons one might prefer to use an enum.
If this is old code, then enum might have been used for the "enum hack".
You can learn more about the "enum hack", for example, in this link: enum hack
In short: this allows defining the value once, just like #define or defining a variable, but unlike #define - here the compiler makes sure that the value is a number (int, r-value) and prevents you from doing all kinds of mischief that you can do with the precompiler's simple "search and replace", and unlike defining a variable - never takes up space under any compiler or configuration, and prevents changes to it (even const variables can sometimes be changed if you try hard enough).
(1) int color = 1;
color is changeable (accidently).
(2) enum { color = 1 };
color cannot be changed.
The other option for enum is,
const int color = 1; // 'color' is unmutable
Both enum and const int offer exactly same concept; it's a matter of choice. With regards to popular belief that enums save space, IMO there is no memory constraint related to that, compiler are smart enough to optimize const int when needed.
[Note: If someone tries to use const_cast<> on a const int; it will result in undefined behavior (which is bad). However, the same is not possible for enum. So my personal favorite is enum]
One use of this is when you're doing template metaprogramming, because enum objects are not lvalues, while static const members are. It also used to be a common workaround for compilers that didn't let you initialize static integral constants in the class definition. This is explained in another question.
When you use
enum {color = 1}
you're not using any memory it's like
#define color 1
If you declare a variable
int color=1
Then you're taking up memory for a value that's not to be changed.
Answer
Readability and performance.
Details are describbed as notes to examples below.
Use cases
Personal example
In Unreal Engine 4 (C++ game engine), I have following property (engine exposed member variable):
/// Floor Slope.
UPROPERTY
(
Category = "Movement",
VisibleInstanceOnly,
BlueprintGetter = "BP_GetFloorSlope",
BlueprintReadOnly,
meta =
(
ConsoleVariable = "Movement.FloorSlope",
DisplayName = "Floor Slope",
ExposeOnSpawn = true,
NoAutoLoad
)
)
float FloorSlope = -1.f;
This is a value of floor slope player is standing on (value ∈ [0; 90)°), if any.
Because of engine limitations, it cannot be neither std::optional nor TOptional.
I've came up with a solution to add another self explainable variable bIsOnFloor.
bool bIsOnFloor = false;
My C++ only internal setter for FloorSlope takes the following form:
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);
};
Adding special case where FloorSlope parameter would take argument of -1.f would be hard to guess and not user friendly.
Instead, I'd rather create False enum field:
enum { False };
This way, I can simply overload SetFloorSlope function that takes intuitive False instead of -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: —";
};
When a player character hits a floor upon applying gravity to it on tick, I simply call:
SetFloorSlope(FloorSlope);
… where FloorSlope is a float value ∈ [0; 90)°.
Otherwise (if it does not hits a floor), I call:
SetFloorSlope(False);
This form (as opposed to passing -1.f) is much more readable, and self explanatory.
Engine example
Another example may be to prevent or force initialization.
Mentioned above Unreal Engine 4 commonly uses FHitResult struct containing information about one hit of a trace, such as point of impact and surface normal at that point.
This complex struct calls Init method by default, setting some values to certain member variables. This can be forced or prevented (public docs: FHitResult #constructor):
FHitResult()
{
Init();
}
explicit FHitResult(float InTime)
{
Init();
Time = InTime;
}
explicit FHitResult(EForceInit InInit)
{
Init();
}
explicit FHitResult(ENoInit NoInit)
{
}
Epic Games defines such enums similiar, but adds redundant enum names:
enum EForceInit
{
ForceInit,
ForceInitToZero
};
enum ENoInit {NoInit};
Passing NoInit to the constructor of FHitResult prevents initialization, what can lead to performance gain by not initializing values that will be initialized elsewhere.
Community example
FHitResult(NoInit) usage in DamirH's post on Comprehensive GameplayAbilities Analysis Series:
//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)
{
}
// (…)
I dont see it mentioned, another use is to scope your constants. I currently work on code that was written using Visual Studio 2005, and it is now ported to android - g++. In VS2005 you could have code like this enum MyOpts { OPT1 = 1 }; and use it as MyOpts::OPT1 - and compiler did not complain about it, even though it is not valid. g++ reports such code as error, so one solution is to use anonymous enum as follows: struct MyOpts { enum {OPT1 =1}; };, and now both compilers are happy.
I recently wrote a class that renders B-spline curves. These curves are defined by a number of control points. Originally, I had intended to use eight control points, so I added a constant to the class, like so:
class Curve
{
public:
static const int CONTROL_POINT_COUNT = 8;
};
Now I want to extend this class to allow an arbitrary amount of control points. So I want to change this to:
class Curve
{
public:
int getControlPointCount() {return _controlPointCount;}
};
The question is whether it isn't better to store constants in methods to begin with, to facilitate adaptability. In other words, isn't it better to have started thus:
class Curve
{
public:
int getControlPointCount() {return 8;}
};
The advantage of this is that I could have just changed one symbol in the method in question, instead of moving around constants etc.
Is this a good practice or a bad one?
int getControlPointCount() {return _controlPointCount;}
This is an accessor. Swapping a const static for an accessor is not really a gain as litb has pointed out. What you really need to future-proof is probably a pair of accessor and mutator.
int getControlPointCount() {return _controlPointCount;} // accessor
I'd also throw in a design-const for the accessor and make it:
int getControlPointCount() const {return _controlPointCount;} // accessor
and the corresponding:
void setControlPointCount(int cpc) { _controlPointCount = cpc;} //mutator
Now, the big difference with a static object is that the control-point count is no longer a class-level attribute but an instance level one. This is a design change. Do you want it this way?
Nit: Your class level static count is public and hence does not need an accessor.
Typically I favour maintaining as few couplings manually as possible.
The number of control points in the curve is, well, the number of control points in the curve. It's not an independent variable that can be set at will.
So I usually would expose a const standard container reference:
class Curve
{
private:
std::vector<Point>& _controlPoints;
public:
Curve ( const std::vector<Point>& controlPoints) : _controlPoints(controlPoints)
{
}
const std::vector<Point>& getControlPoints ()
{
return _controlPoints;
}
};
And if you want to know how many control points, then use curve.getControlPoints().size(). I'd suspect that in most of the use cases you'd want the points as well as the count anyway, and by exposing a standard container you can use the standard library's iterator idioms and built-in algorithms, rather getting the count and calling a function like getControlPointWithIndex in a loop.
If there really is nothing else in the curve class, I might even go as far as:
typedef std::vector<Point> Curve;
(often a curve won't render itself, as a renderer class can have details about the rendering pipeline, leaving a curve as purely the geometric artifact)
To better answer your question, one should also know how the controlPointCount variable is set. Is it set outside from your class? In this case, you should also define a setter. Or the Curve class is the sole responsible for setting it? Is it set only on compile time or also on runtime.
Anyway, avoid a magic number even in this form:
int getControlPointCount() {return 8;}
This is better:
int getControlPointCount() {return CONTROL_POINT_COUNT;}
A method has the advantage that you can modify the internal implementation (use a constant value, read from a configuration file, alter the value dynamically), without affecting the external of the class.
class Curve
{
private:
int _controlPointCount;
void setControlPointCount(int cpc_arg)
{
_controlPointCount = cpc_arg;
}
public:
curve()
{
_controlPointCount = 8;
}
int getControlPointCount() const
{
return _controlPointCount;
}
};
I will create a code like this, with set function in private, so that no body can play with control point count, until we move to the next phase of development..where we update start to update the control point count at runtime. at that time, we can move this set method from private to public scope.
While understanding the question, I have a number of conceptual problems with the example:
What is the return value for getControlPointCount() when the number of control points is not limited?
Is it MAXINT?
Is it the current number of control points on the curve (thus breaking the logic that says that this is the largest possible number of points?)
What happens when you actually attempt to create a curve with MAXINT points? You will run out of memory eventually.
The interface itself seems problematic to me. Like other standard collection classes, the class should have encapsulated its limitation on number of points, and its AddControlPoint() should have returned an error if a limitation on size, memory, or any other violation has occurred.
As for the specific answer, I agree with kgiannakakis: a member function allows more flexibility.
I tend to use configuration + constant (default value) for all 'stable' values through the execution of the program. With plain constants for values that cannot change (360 degrees -> 2 pi radians, 60 seconds -> 1 minute) or whose change would break the running code (minimum/maximum values for algorithms that make them unstable).
You are dealing with some different design issues. First you must know whether the number of control points is a class or instance level value. Then whether it is a constant at any of the two levels.
If all curves must share the same number of control points in your application then it is a class level (static) value. If different curves can have different number of control points then it is not a class level value, but rather a instance level one.
In this case, if the number of control points will be constant during the whole life of the curve then it is a instance level constant, if it can change then it is not constant at this level either.
// Assuming that different curves can have different
// number of control points, but that the value cannot
// change dynamically for a curve.
class Curve
{
public:
explicit Curve( int control_points )
: control_points_( control_points )
{}
// ...
private:
const int control_points_;
};
namespace constant
{
const int spline_control_points = 8;
}
class Config
{
public:
Config();
void readFile( std::string const & file );
// returns the configured value for SplineControlPoints or
// constant::spline_control_points if the option does not
// appear in config.
int getSplineControlPoints() const;
};
int main()
{
Config config;
config.readFile( "~/.configuration" ); // read config
Curve c( config.getSplineControlPoints() );
}
For integral type I'm usualy using:
class Curve
{
public:
enum
{
CONTROL_POINT_COUNT = 8
};
};
If constant doesn't need for any entities except class implementation I declare constants in *.cpp file.
namespace
{
const int CONTROL_POINT_COUNT = 8;
}
In general, all your data should be private and accessed via getters and setters. Otherwise you violate encapsulation. Namely, if you expose the underlying data you lock yourself and your class into a particular representation of that underlying data.
In this specific case I would have done the something like the following I think:
class Curve
{
protected:
int getControlPointCount() {return _controlPointCount;}
int setControlPointCount(int c) { _controlPointCount = c; }
private:
static int _controlPointCount = 0;
};
Constants in general should not be defined inside methods. The example you're choosing has two unique features. First, it's a getter; second, the type being returned is an int. But the point of defining constants is to use them more than once, and to be able to refer to them in a convenient way. Typing "8" as opposed to "controlPointCount" may save you time, and may not seem to incur a maintenance cost, but this won't typically be true if you always define constants inside methods.