static const Member Value vs. Member enum : Which Method is Better & Why? - c++

If you want to associate some constant value with a class, here are two ways to accomplish the same goal:
class Foo
{
public:
static const size_t Life = 42;
};
class Bar
{
public:
enum {Life = 42};
};
Syntactically and semantically they appear to be identical from the client's point of view:
size_t fooLife = Foo::Life;
size_t barLife = Bar::Life;
Is there any reason other than just pure style concerns why one would be preferable to another?

The enum hack used to be necessary because many compilers didn't support in-place initialization of the value. Since this is no longer an issue, go for the other option. Modern compilers are also capable of optimizing this constant so that no storage space is required for it.
The only reason for not using the static const variant is if you want to forbid taking the address of the value: you can't take an address of an enum value while you can take the address of a constant (and this would prompt the compiler to reserve space for the value after all, but only if its address is really taken).
Additionally, the taking of the address will yield a link-time error unless the constant is explicitly defined as well. Notice that it can still be initialized at the site of declaration:
struct foo {
static int const bar = 42; // Declaration, initialization.
};
int const foo::bar; // Definition.

They're not identical:
size_t *pLife1 = &Foo::Life;
size_t *pLife2 = &Bar::Life;

One difference is that the enum defines a type that can be used as a method parameter, for example, to get better type checking. Both are treated as compile time constants by the compiler, so they should generate identical code.

static const values are treated as r-values just like enum in 99% of code you'll see. Constant r-values never have memory generated for them. The advantage enum constants is they can't become l-values in that other 1%. The static const values are type safe and allow for floats, c-strings, etc.
The compiler will make Foo::Life an l-value if it has memory associated with it. The usual way to do that is to take its address. e.g. &Foo::Life;
Here is a subtle example where GCC will use the address:
int foo = rand()? Foo::Life: Foo::Everthing;
The compiler generated code uses the addresses of Life and Everything. Worse, this only produces a linker error about the missing addresses for Foo::Life and Foo::Everything. This behavior is completely standard conforming, though obviously undesirable. There are other compiler specific ways that this can happen, and all standard conforming.
Once you have a conforming c++11 compiler the correct code will be
class Foo {
public:
constexpr size_t Life = 42;
};
This is guaranteed to always be an l-value and it's type-safe, the best of both worlds.

Well, if needed, you can take the address of a static const Member Value. You've have to declare a separate member variable of enum type to take the address of it.

Another third solution?
One subtle difference is that the enum must be defined in the header, and visible for all. When you are avoiding dependencies, this is a pain. For example, in a PImpl, adding an enum is somewhat counter-productive:
// MyPImpl.hpp
class MyImpl ;
class MyPimpl
{
public :
enum { Life = 42 } ;
private :
MyImpl * myImpl ;
}
Another third solution would be a variation on the "const static" alternative proposed in the question: Declaring the variable in the header, but defining it in the source:
// MyPImpl.hpp
class MyImpl ;
class MyPimpl
{
public :
static const int Life ;
private :
MyImpl * myImpl ;
}
.
// MyPImpl.cpp
const int MyPImpl::Life = 42 ;
Note that the value of MyPImpl::Life is hidden from the user of MyPImpl (who includes MyPImpl.hpp).
This will enable the MyPimpl author to change the value of "Life" as needed, without needing the MyPImpl user to recompile, as is the overall aim of the PImpl.

Related

const declaration inside the class

to avoid complicated linker rules, C++ requires that every object has
a unique definition. That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
I'm having hard time understanding this:
class Y {
const int c3 = 7; // error: not static
static int c4 = 7; // error: not const
static const float c5 = 7; // error: not integral
static const int c6 = 7;
};
How does const int c6 = 7; break following rule?
C++ requires that every object has
a unique definition.
And static const int c6 = 7; do not break it (enums too)?
Please also explain why static const float c5 = 7; is not allowed but static const int c5 = 7; is allowed?
A lot of these rules have been changing over time, so it really depends on the version of C++ you are using. Also, some of these may not be technically impossible, but the committee simply decided against them because they might be hard to implement, or are prone to errors. So you might not always get the most satisfying answer on why thing are the way they are.
Lets go over them one by one.
Const Member
class Foo
{
const int bar = 7;
};
This used to be illegal before C++11. Before that version you were only allowed to initialize static variables in their declaration. If you are still not on C++11, my condolences. More details can be found here.
Static Member
class Foo
{
static int bar = 7;
};
Another one that changed, but more recently. Before C++17 it was illegal to initialize non const static variables in their declaration. This has to do with the one definition rule. When the header containing this class is included in multiple translation units (.cpp files), which one should be responsible for initializing the value? This is why you have to place the definition somewhere in a single .cpp file.
After C++17 you are allowed to do this:
class Foo
{
inline static int bar = 7;
};
When you use inline like this it somehow figures out how to only initialize it once. More details can be found here.
Static Const Float Member
class Foo
{
static const float bar = 7.0f;
};
This has mainly to do with the unpredictability of floats when you run into floating point errors. An example:
class Foo
{
static const float bar = 0.1f;
};
Since 0.1f is impossible to represent in most floating point implementations, you won't get exactly 0.1f, but only something very close to it. This can then result in different behaviors on different systems that have slightly different implementations, causing your program to run differently depending on the system.
This gets even worse when the value is the result of a calculation, because (a*b)*c is not guaranteed to be the exact same value as a*(b*c), even though it might seem like they are.
But const static floats are still allowed when you define the value outside of the class, so technically it would all still be possible to implement. But the committee never did, probably because it would cause more problems than it would solve. This is also similar to why you are allowed to use integral types as template parameters, but not floats.
template <int i> class Foo {}; // Good
template <float f> class Bar {}; // Bad
However, the committee seems to have changed it's opinion somewhat, since we are now allowed to use floats with constexpr. So it can be done if you write this instead:
class Foo
{
static constexpr float bar = 7.0f;
};
Conclusion
All of these are actually possible in some form with the right version of C++ and the right syntax. Just keep in mind the potential issues described above, and you should be good to go.
Let go through it.
FIRST READ BELOW THEN COME TO CODE
class Y {
const int c3 = 7; // It's fine. If you write good constructor.
// static int c4 = 7; // error: not const as it is trying to initialize with object constructor which it shouldn't
static const float c5 = 7; // error: not integral as we can do it for integral type only. To correct this you can do.
static constexpr float c5 = 7; // we should use constexpr for literal type.
static const int c6 = 7; // it was fine as both types are same int and 6 where it was not the case in 1st case.
};
int main()
{
Y y;
}
First, learn these lines
a. When we create a const object of a class type, the object does not
assume its constness until after the constructor completes the object's initialization.
Thus, constructors can write to const objects during their construction.
So this will yield an error.
class Const {
public:
Const(int ii);
private:
int i;
const int ci;
};
ConstRef::ConstRef(int ii)
{ // assignments:
i = ii; // ok
ci = ii; // error: cannot assign to a const
}
**TO CORRECT THIS YOU SOULD DO**
Const::Const(int ii): i(ii), ci(ii) { } // this is how constructor should be
Let's discuss everything one by one.
Your fist member is already excellent. It should work fine as per my knowledge, and it's working for me. I think it's not working for you because your constructor is trying to initialize it in the constructor body, which you can't.
We must use the constructor initializer list to provide values for members that
are const, reference, or of a class type that does not have a default
constructor.
Let come to the static part
We say a member is associated with the class by adding the keyword static to its declaration.
The static members of a class exist outside any object.
static member functions are not bound to any object; they do not have
a this pointer. As a result, static member* functions* may not be declared as const, and we may not refer to this in the body of a static member. This restriction applies both to explicit uses of this and to implicit uses of this by calling
a nonstatic member.
IMP
Because static data members are not part of individual objects of the class type, they are not defined when we create objects of the class. As a result, they are not initialized by the class’ constructors. Moreover, in general, we may not initialize a static member inside the class.
So i think you got your second error reason. You are trying to initialize it with object constructor.
Let's go to the third one.
Ordinarily, class static members may not be initialized in the class body. However, we can provide in-class initializers for static members that have const integral
type and must do so for static members that are constexprs of literal type. The initializers must be constant expressions.
So.
static constexpr float c = 7; this is fine. You can check
I hope it' clear now. Let m know if you still got issues. Btw i skipped indirect concept too. But for depth understanding you need to learn about ``literal class`.

const object or private/const data members (variables) in C++?

We know that const object members cannot be modified once declared but what is the real use of them? We can individually declare variables to be const inside the class or declare them private.
If there is any other significance of const object in C++, then please mention that too.
To answer your question literally:
If you make members of a class const, that applies to every instance of the class, but only to the members that you made const.
If you make an object const, that applies to a single instance of that class, but it does apply to all members of that instance.
const is one of the most elementary subjects in C++, in my opinion. Something that is way too often overlooked.
Generally const has three use cases:
Allowing the compiler to optimize more aggressively
Allowing the compiler to point out our mistakes when we accidentally try to change a const value
Convey intend by specifying that we do not want an object changed
In the case of a const member of a class, we force the object to be initialized during instantiation of the class. Preventing us from accidentally changing it's value in member functions. Which is the big difference to just using a private member variable. We still can accidentally change a private member variable anywhere inside the class.
One of the most useful ways to use const is with parameters:
This can allow major optimization for the compiler, for various reasons that are out of scope of this answer.
And in the case of const references, the compiler can prevent you from accidentally changing the value of that reference.
Most importantly, it allows you to define the signature of your function in a more clarifying way.
I luckily use this once(so far). And i never thought i would need to use a const in a member variable.
class TypeA {
protected:
DataX const* m_data; //get a pointer to a data that shouldn't be modified even inside the class.
public:
TypeA(DataX const* p){
m_data = p;
}
auto& getData(){ return *m_data; } //will return DataX const&
}
For the private member variables, i think they are best for helper-variables in the current class that are really not part of the object logically. Maybe for caching, temporary holder of some data that should be there for a time duration, a counter for an algorithm, etc. And they are only used and should be used in the current class. You don't want other programmers to use them in the derived class because they have a very special use so you hide them in private.
Another example for const member are for constant values aside for enums. I prefer enum over a variable that takes storage but some programmer prefer following on what they used to however you convinced them not to(maybe i'm wrong, and they are really correct, and maybe in the future for some reason the const in the language changed, and then using const might be better.)
class TypeA {
public:
const int HEY_VALUE = 101;
const int YOH_VALUE = 102;
const int HELP_VALUE = 911;
const float MIN_SOMETHING = 0.01;
static const int HELLO_EARTH = 10;
//...
}
I can't find this specific code of mine, but i think i used & instead of const*. I used it like this.
class TypeA {
protected:
DataX& m_data;
public:
TypeA(DataX& p):m_data(p){ //you can only set this once in the constructor
}
auto& getData(){ return m_data; } //will return DataX const&
}
I really prefer using . instead of -> for personal reasons so I really pushing myself to achieve the syntax i want and i came with these weird solutions. It's fun because I discovered that those weird approaches are still valid and achievable in c++.
Update
If there is any other significance of const object in C++, then please mention that too.
Maybe you can const some filler bytes on specific part of the class.
class TypeA {
protected:
const int HEADER_BYTES = 0x00616263;
int m_data1;
int m_data2;
const uint8_t ANOTHER_FILLER_FOR_SOME_REASON = 0xffffffff; //maybe forcing offset address, or alignment, etc.
int m_anotherData;
}
Generally, const keyword is being used to improve readability of the code you are writing.
However, in some cases const can also allow compiler optimizations. Let's see the following code snippet:
int const i = 1;
fun(&i);
printf("%d\n", i);
Here, trying to modify the variable i would cause an Undefined Behaviour. Therefore, the compiler will assume modification won't be even tried so it will pass the value 1 to the printf function.
Same is valid for const data members.

Is private const redundant in a C++ class?

Suppose I have a class with a member variable that I don't want to be changed. Is there any difference between making that variable a private const and just making the variable private, assuming there is no setter function?
Private:
class ConstFoo
{
public:
Foo(int a);
virtual ~Foo();
int val(){ return val_; }
private:
int val_;
}
Private Const:
class ConstFoo
{
public:
Foo(int a);
virtual ~Foo();
int val(){ return val_; }
private:
const int val_;
}
It seems that there is no difference between the two, since you can't change the value of val_ in either case, so the const qualifier seems redundant.
The one reason I can see to explicitly add const is for code clarity, so people working on the code in the future don't add a setter to the function. However, with the name as ConstFoo and documentation specifically stating that it is not meant to be mutable, I don't think this will be an issue.
It's all a matter of how "const" you want this value to be.
As it currently stands, no external user can directly change the value. But they can do so indirectly, because the object itself may not be const:
ConstFoo a{0};
ConstFoo b{2};
a = b;
a now has 2 in it.
Plus, code within ConstFoo can change its value too; this is why the copy assignment operator can change its value.
So if you want to ensure that the specific member object will assume one value throughout the lifetime of any ConstFoo instance, you declare it const.
Of course, this makes ConstFoo non-assignable.
You correct that no outsider can change the member if it is private. This does not mean though that it can't be changed. If you had another member function like
void bar() { val_ = 42; }
Then your first code block would compile while the second one would give you an error. If you truly do not want to be able to change the value of the member then it should be const regardless if it is private or not. That const will act as a bug checker for you.
You've pretty much answered it yourself: making it const expresses your intention very clearly, and give the compiler the ability to back you up.
In my humble opinion, the const keyword serves two purposes:
A) It shows the programmers intent that this value is not to be changed once it's been set,
B) It allows the compiler to enforce that intent, thereby preventing mistakes.
Naming it constFoo somewhat achieves the first of these but does nothing for the second. And is (again IMHO) significantly more ugly than using const.
Not sure, if i get your question right, but generally speaking:
private members can only be accessed from inside the class itself, whereas public members can be accessed from the outside
const members can only be set once inside the constructor when creating a new object of this specific class
That means, a private const variable could be set once when creating a new object of this class and could therefor act as an internal modifier (e.g. giving a offset to certain functions provided by that class) valid over the whole lifetime of this object.
A mere private variable could change its value from inside the class and therefor.
Also generally speaking you are completely right, the whole concept of using constants in C++ is for making sure, your constraints are complied to in the further development process (not only by other developers, also by yourself)
The private keyword makes sure noone outside the class can modify the variable.
If you don't modify the variable inside the class then the result is the same.
As my opinion it is better to use the keywork const too because not only it is telling to the developers (including yourself) who might modify your class that it is intended to remain constant but it is also more secure: if they try modify the modification will not have effect.
So in my opinion it is not redundant.

Usage of const data member in C++

Well, I know the functionality of const data member in a C++ class.
What I want to know is, the purpose of introducing a const data member in a class. Why someone will use that while writing a real software? What are the real-life usage of const data members?
Please give me a few real life examples with reasons.
EDIT :
I am not asking about static const data member.
I am asking for some real life use cases where each object will be having a different const value for same data.
You'd use a const data member for the same reason that you'd use any const object: for a value that may be arbitrarily initialised but then never changed.
A good rule of thumb is to denote something as const "by default", so you can picture plenty of reasons to use it in a class.
class User
{
User(const std::string& name)
: name(name)
{}
private:
/**
* User's name is an invariant for the lifetime of this object.
*/
const std::string name;
};
Can you leave out the const here? Yeah, sure. But then you may accidentally change name when you didn't mean to. The entire purpose of const is to protect against such accidents.
However, sadly, your class will not be assignable!
There are several cases. The most obvious one is a static const data member. These are used as scoped constants:
class Something {
static const int SOME_CONSTANT = 17;
};
Note that under C++11 and onward, constexpr usually makes more sense in those cases.
This defines a constant that is typed and scoped to the class' implementation. I suspect this was not what you were asking, however.
The more interesting use case is for values that are different between instances of the class, but constant across the class' lifetime.
For example, suppose you have a RAID implementation, where a configuration sets the stripe width. You do not know the stripe width at compile time, so the above construct will not help you. You do want the width to remain constant throughout the class' lifetime however (maybe your code doesn't know how to handle stripe width changes).
In those cases, marking the value const, and setting it in the constructor, can give you compile time guarantee that no one is changing this value.
You use it exactly the same as you would use a globally declared const, only you want it to only apply to the class you have defined it in. For example
class Character
{
public:
Character()
:
mCurrentHealth{TOTAL_HEALTH},
mCurrentMana{TOTAL_MANA}
{
}
// Define lose/gain health/mana functions
// for mCurrentHealth and mCurrentMana
private:
int mCurrentHealth;
int mCurrentMana;
// Constants
const int TOTAL_HEALTH = 100;
const int TOTAL_MANA = 50;
};
There are many other examples, but the main point is that we don't want TOTAL_HEALTH and TOTAL_MANA defined outside the class, because they won't be relevant.

Is it better to replace constants by template parameters?

Is it better to do:
const int MY_CONST = 20; // global constant in the program
class A {
// uses MY_CONST all over the class implementation and definition
}
or this?
const int MY_CONST = 20; // global constant in the program
template<int my_const>
class A {
//uses my_const only and never MY_CONST
};
//A<MY_CONST> used later in the program
Is one of these pattern better than the other? why?
thanks
Unless that global constant is used elsewhere outside of the class I would use neither of those approaches and make the constant a member of A:
class A {
public:
static const int MY_CONST = 20;
};
const int A::MY_CONST; // Possibly need definition also
And then use A::MY_CONST in your code.
The only time I would use a template is when you need to change the value depending on the instance for some reason.
template <int I>
class A
{
public:
static const int MY_CONST = I;
};
template <int I>
const int A<I>::MY_CONST; // Definition
Then create instances like so:
A<1> a1;
A<2> a2;
The second solution is sensible if it makes sense to instantiate e.g. A<MY_CONST + 1>, or A<0>, or any other value than MY_CONST. If, however, A is strictly designed to be used with the one value, then you don't gain anything from that. In that respect the first solution gives you everything you need.
One way to look at it is that you're introducing a dependency to A (only on a number, not on anything with behavior, but still that's a kind of dependency), and the question is whether to inject that dependency via a template parameter, or have the class pull in the dependency via a named const object.
I can see the template being useful for testing the class A -- you want to write the class to work with any value, so that you can change the value in future with confidence that you won't immediately get test failures and have to fix the bugs.
So, you could write the template and test it with lots of different values, even though no "real" program will use more than one instantiation of the template.
Obviously there are other ways to write a class whose behavior depends on an integer value, and test it. For example you could use a macro and have the test harness compile the code multiple times, or you could make MY_CONST an extern value and link the code against different object files containing different values, or you could make A store the value as a data member (even a static data member).
Which ones work for you depends how the class is going to use the value, but since a template parameter is an integer constant expression it's good for most uses that the const int is good for. You can't take a template parameter's address, is the only thing that immediately springs to mind.
I would always remove the global variable. Let's distinguish 2 cases, MY_CONST is either
an implementation detail in which case I would prefer to make it a private constant
class A
{
private:
static int const MY_CONST = 20;
};
or part of the class interface in which case I would prefer to make it a template parameter and provide it as a public member
template<int N>
class A
{
public:
static int const MY_CONST = N;
};
This way, users can not only read but also "write" (at compile-time) to MY_CONST. If users will not want to specify anything but a default value for N, you could provide a default template argument, or give a simple typedef
typedef A<20> DefaultA;