Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ const getter method with lazy initialization

What is the proper way to implement a getter method for a lazily-initialized member variable and maintain const-correctness? That is, I would like to have my getter method be const, because after the first time it is used, it's a normal getter method. It is only the first time (when the object is first initialized) that const does not apply. What I would like to do:

class MyClass {   MyClass() : expensive_object_(NULL) {}   QObject* GetExpensiveObject() const {     if (!expensive_object_) {       expensive_object = CreateExpensiveObject();     }     return expensive_object_;   } private:   QObject *expensive_object_; }; 

Can I eat my cake and have it too?

like image 273
Dave Mateer Avatar asked Jul 30 '10 19:07

Dave Mateer


2 Answers

I propose encapsulating James Curran's answer into a class of its own if you do this frequently:

template <typename T> class suspension{    std::tr1::function<T()> initializer;    mutable T value;    mutable bool initialized; public:    suspension(std::tr1::function<T()> init):       initializer(init),initialized(false){}    operator T const &() const{       return get();    }    T const & get() const{       if (!initialized){          value=initializer();          initialized=true;       }       return value;    } }; 

Now use this in your code as follows:

class MyClass {   MyClass() : expensive_object_(CreateExpensiveObject) {}   QObject* GetExpensiveObject() const {     return expensive_object_.get();   } private:   suspension<QObject *> expensive_object_; }; 
like image 93
Ken Bloom Avatar answered Sep 18 '22 14:09

Ken Bloom


That's fine and is the typical way of doing it.

You will have to declare expensive_object_ as mutable

mutable QObject *expensive_object_;  

mutable basically means "I know I'm in a const object, but modifying this won't break const-ness."

like image 34
James Curran Avatar answered Sep 17 '22 14:09

James Curran