Is it possible to initialize a static const member of my class during run-time? This variable is a constant throughout my program but I want to send it as a command-line arg
N - O
The semantics of what is being required are all wrong, and you shouldn't use a static-const for that.
A static is an object or integral type which has static storage duration and internal linkage.
A const is an object that does not change its value throughout application's lifetime, any attempt to change it results in UD . ( the overwhelming majority of such cases is a pretty well defined crash )
As a result of this question dangerous workarounds have been proposed to mimic the implied behavior. In most of examples a static-const-reference is given a somehow hidden static which is assignable at runtime, e.g. this.
Apart from the difficulties in maintaining such code, the problem remains that declared semantics are not actually enforced.
For example in keeping the value const throughout the application runtime can be hacked by doing const_cast<int &>(A::T) = 42
, which is perfectly valid, perfectly define code since the referenced type is not const.
What is being sought after here is an class that permits to be initialized only once throughout the application, has internal linkage, and the lifetime of the application.
So just do a template class that does that:
template<typename V> class fixation
{
bool init = true;
V val;
public:
fixation(V const & v) : init(true), val(v) {}
fixation & operator=( fixation arg)
{
if(init )
{
this->val = arg.val;
}
this->init = false;
return *this;
}
V get()
{
return val;
}
};
struct A
{
static fixation<int> T;
};
How to handle the case that it is called a second time, that is an implementation decision. In this example the value is totally ignored. Others may prefer to throw an exception, do an assertion, ... etc.
const
reference to it (as shown by dasblinkenlight):class A {
public:
static const int &T;
};
static int dummy = 0;
const int &A::T = dummy;
int main() {
dummy = 10;
std::cout << A::T << std::endl;
}
Live Demo
const
static member (as shown by R Sahu):class A {
public:
static int T;
};
int A::T = 0;
int main() {
A::T = 10;
}
Live Demo
class A {
friend void foo(int);
static int dummy;
public:
static const int &T;
};
const int &A::T = A::dummy;
int A::dummy = 0;
void foo(int val) { A::dummy = val; }
int main() {
foo(10);
std::cout << A::T << std::endl;
}
Live Demo
class A {
static int dummy;
public:
static const int &T;
static void foo(int val) { A::dummy = val; }
};
const int &A::T = A::dummy;
int A::dummy = 0;
int main() {
A::foo(10);
std::cout << A::T << std::endl;
}
Live Demo
If you want to initialize only once you can change the helper function to:
static void foo(int val) {
static bool init = true;
if(init) A::dummy = val;
init = false;
}
Live Demo
No, since you defined the variable as static and const, you cannot change its value. You will have to set its value in the definition itself, or through a constructor called when you create an object of class A.
I am sorry to disagree with the comments and answers saying that it is not possible for a static const
symbol to be initialized at program startup rather than at compile time.
Actually this IS possible, and I used it many times, BUT I initialize it from a configuration file. Something like:
// GetConfig is a function that fetches values from a configuration file
const int Param1 = GetConfig("Param1");
const int MyClass::Member1 = GetConfig("MyClass.Member1");
As you see, these static consts are not necessarily known at compile time. They can be set from the environment, such as a config file.
On the other hand, setting them from argv[], seems very difficult, if ever feasible, because when main() starts, static symbols are already initialized.
Having been facing the same problem myself lately I found @A.S.H 's answer to be the closest to perfect but the fact that the variables have to be initialized so early can cause some problems:
argc
and argv
as per the question.So I came up with the following:
template <class T>
class StaticConfig
{
public:
StaticConfig()
{
if (!mIsInitialised)
{
throw std::runtime_error("Tried to construct uninitialised StaticConfig!");
}
}
const T*
operator -> () const
{
return &mConfig;
}
private:
friend class ConfigHandler;
StaticConfig(const T& config)
{
mConfig = config;
mIsInitialised = true;
}
static T mConfig;
static bool mIsInitialised;
};
template <class T>
T StaticConfig<T>::mConfig;
template <class T>
bool StaticConfig<T>::mIsInitialised = false;
We make our data static but non-const so we don't have to initialize it immediately and can assign the correct values to it at a more opportune time. Read only access is given trough a overload of operator ->
The default constructor checks if a StaticConfig
of this type has already been loaded with valid data and throws if it is not. This should never happen in practice but serves as a debugging aid. A private constructor allows loading the type with valid data. A ConfigHandler
class, responsible for loading the data, is made a friend so it can access the private constructor.
A ConfigHandler
instance can be briefly created at an opportune time when all the dependencies are available to initialize all the StaticConfig
types. Once done, the ConfigHandler
instance can be discarded. After that, a class can simply include the appropriate type of StaticConfig
as a member and read-only access the data with minimal intrusion.
Online demonstration.
No, you cannot do that.
If this cannot be done what is the type of variable I should use ?
You can use a non-const
member.
class A
{
public:
static int T;
};
int A::T;
Another option is to make T
a private member, make main
a friend so only it can modify the value, and then expose the member through a function.
#include <cstdlib>
class A
{
public:
static int getT() { return T; }
private:
static int T;
friend int main(int argc, char** argv);
};
int A::T;
int main(int argc, char** argv)
{
A::T = std::atoi(argv[1]);
return 0;
}