Can I initialize a static const member at run-time

2019-01-18 09:47发布

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 argument.

//A.h
class A {
public: 
    static const int T;
};

//in main method
int main(int argc,char** argv)
{
    //how can I do something like 
    A::T = atoi(argv[1]);
}

If this cannot be done, what is the type of variable I should use? I need to initialize it at run-time as well as preserve the constant property.

10条回答
时光不老,我们不散
2楼-- · 2019-01-18 10:23

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;
}
查看更多
干净又极端
3楼-- · 2019-01-18 10:26

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.

查看更多
乱世女痞
4楼-- · 2019-01-18 10:30

You cannot rely on data produced after your main has started for initialization of static variables, because static initialization in the translation unit of main happens before main gets control, and static initialization in other translation units may happen before or after static initialization of main translation unit in unspecified order.

However, you can initialize a hidden non-const variable, and provide a const reference to it, like this:

struct A {
public: 
    // Expose T as a const reference to int
    static const int& T;
};

//in main.cpp

// Make a hidden variable for the actual value
static int actualT;
// Initialize A::T to reference the hidden variable
const int& A::T(actualT);

int main(int argc,char** argv) {
    // Set the hidden variable
    actualT = atoi(argv[1]);
    // Now the publicly visible variable A::T has the correct value
    cout << A::T << endl;
}

Demo.

查看更多
祖国的老花朵
5楼-- · 2019-01-18 10:30

Typically you will have more than one configuration value. So put them in a struct, and the normal global access to it is const.

const config* Config;
...
main (int argc, char* argv [])
{
Config= new config (argc, argv);
...
}

You can get fancier and have a global function to return config, so normal code can't even change the pointer, but it is harder to do that by accident.

A header file exposes get_config () for all to use, but the way to set it is only known to the code that's meant to do so.

查看更多
爷、活的狠高调
6楼-- · 2019-01-18 10:32

Method #1: Initialize a hidden non-const variable, and provide a 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

Method #2: Use a non 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

Method #3: Declare a hidden non-const variable as a private static member of your class and provide a static member const reference to interface it. Define a friend function as inititalizer:

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

Method #4: Declare a hidden non-const variable as a private static member of your class and provide a static member const reference to interface it. Define a static member function as inititalizer:

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

Bonus:

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

查看更多
干净又极端
7楼-- · 2019-01-18 10:38

Not only you can't, you should not try doing this by messing with const_cast. Static const members have a very high chance of ending up in read-only segment, and any attempt to modify them will cause program to crash.

查看更多
登录 后发表回答