One Two Three
One Two Three

Reputation: 23497

ensure static members are set at most once (C++)

class Foo {
   public:
     static int& num() {
          static int aNum = 0; // initial value
          return aNum;
     }

     static void writer_func() { /* ... do stuff and assign a value to num() */ }

     // a bunch of functions that "read" num()
     static void reader_func1() { /* uses num() in read-only mode */}
     static void reader_func2() { /* uses num() in read-only mode */}

}

How do I ensure that all the reader_func*() functions do not assign value to num() ?

Addendum: In comments/answers, a few have suggested that I simply declare the field as a simple static int num;. That will not work because it can potentially violate ODR

The reason I had to employ this slightly "odd" pattern is to not violate ODR

Also, the restriction here is that writer_func() will be called by other code, and I can't just preemptively call writer_func() to init the value

Upvotes: 3

Views: 188

Answers (5)

George
George

Reputation: 2120

It's not especially elegant, but since you mention that writer_func could potentially be called more than once, you could do something like:

class Foo {
public:
    static const int& num();

    static void writer_func();

    // a bunch of functions that "read" num()
    static void reader_func1() { /* uses num() in read-only mode */}
    static void reader_func2() { /* uses num() in read-only mode */}

};

class Num {
    static int& num() {
        static int aNum = 0; // initial value
        return aNum;
    }
    friend const int& Foo::num();
    friend void Foo::writer_func();
};

const int& Foo::num() {
    return Num::num();
}

void Foo::writer_func() {
    /* ... do stuff and assign a value to num() */ 
}

Upvotes: 1

Heath Raftery
Heath Raftery

Reputation: 4169

Similar concept to George's suggestion, but with a neater/less sophisticated trade-off: wrap num() in a read-only version and prevent (by extra class funkiness or by a static coding rule) use of num() from reader_func*().

class Foo {
   public:
     static int& num() {
          static int aNum = 0; // initial value
          return aNum;
     }

     static int num_ro() {
          int &aNum = num();
          return aNum;
     }

     static void writer_func() { /* ... do stuff and assign a value to num() */ }

     // a bunch of functions that "read" num()
     static void reader_func1() { /* uses num_ro() in read-only mode */}
     static void reader_func2() { /* uses num_ro() in read-only mode */}

};

Upvotes: 0

Felix Glas
Felix Glas

Reputation: 15524

If we're talking about a compile-time value, then what about making aNum a class-scope static const, e.g.:

class Foo {
public:
    static const int aNum;

    static const int& num() {
        return aNum;
    }

    static int writer_func() { /* ... do stuff and return a value, e.g.: */ return 1; }

    // a bunch of functions that "read" num()
    static void reader_func1() { /* uses num() in read-only mode */}
    static void reader_func2() { /* uses num() in read-only mode */}
};

const int Foo::aNum = Foo::writer_func();

Upvotes: 0

Gabriel
Gabriel

Reputation: 3594

To ensure that you need to create a singleton class and allow modification only once:

class StaticContainer
{
public:
    static void setValue(int val){
        if (!isSet){
             isSet=true;
             value=val;
             std::cout<<"value changed to "<<val<<std::endl;
        }
        else{
            std::cout<<"value cannot be changed\n";    
        }
    }
private:
    static bool isSet;
    static int value;
};

bool StaticContainer::isSet=false;
int StaticContainer::value;
int main()
{
    StaticContainer::setValue(10); 
    StaticContainer::setValue(20);     
}

Output:

value changed to 10

value cannot be changed

Upvotes: 0

R Sahu
R Sahu

Reputation: 206607

One way to deal with it is to create a class that allows one time modification of the value and use an instance of the class.

class OneTimeWrite
{
   public:

      OneTimeWrite() : value_(0), isset_(false) {}

      int get() const { return value_; };

      void set(int v)
      {
         if ( isset_ )
         {
            throw std::runtim_error("Value must not be set more than once.");
         }

         isset_ = true;
         value_ = val;
      }

   private:

      int value_;
      bool isset_;
}

class Foo
{
   public:
     static OneTimeWrite aNum;

     // ...    
}

Upvotes: 0

Related Questions