How to retain value of a local variable in member function but not share between instances

Viewed 222

My question is different from Static variables in member functions.

class A {
public:
    void foo() {
        B b(params_); // It takes lots of time to construct b. b is only used in foo().
        // do something with b
        return;
    }
private:
    int params_;
};

int main() {
    A a1(params1), a2(params2);
    a1.foo(); // call 1
    a1.foo(); // call 2
    a2.foo(); // call 3
}

I want b to be same in call 1 & call 2 and constructed only once and should be seen in foo() only. However b should have different value in call 2 & call 3 due to different value of params_ in a1 and a2. How should I declare b?

  1. static variable in foo(): b has same value across different instances a1, a2. It doesn't meet my requirement.
  2. local variable in foo(): b is constructed every time foo() is called. It doesn't meet my requirement.
  3. member variable of class A: b can be seen by other member functions of A. It doesn't meet my requirement.
  4. other good choice?
1 Answers

You can try this, but I think that it's an ugly trick:

#include <iostream>
#include <map>
#include <memory>

class B {
public:
    B(int src) {
        std::cout << "B constructed from " << src << "." << std::endl ;
    }
    void foo(int i) {
        std::cout << "B.foo(" << i << ") called." << std::endl ;
    }
} ;

class A {
public:
    int inst ;
    A(int v) : inst(v) {}

    void foo() {
        // Static map associating current A instance and a B object.
        static std::map<A*,std::unique_ptr<B>> Bmap ;
        // Search an already existing instance.
        auto b = Bmap.find(this) ;
        if (b==Bmap.end())
            // Not found, create one.
            b = Bmap.insert({this,std::make_unique<B>(B(inst))}).first ;
        // If already an instance of B, returns it, otherwise create it with params_
        // Do something with b.
        b->second->foo(inst) ;
        return;
    }
} ;

int main() {

   A a1(1), a2(2) ;

   a1.foo() ;
   a2.foo() ;
   a1.foo() ;
}

This code compiles and run, it produces that output:

B constructed from 1.
B.foo(1) called.
B constructed from 2.
B.foo(2) called.
B.foo(1) called.

But a member variable would be cleaner and better, even if you use just-in-time initialization and leaves it to nullptr until you really need it.

Related