0

Suppose I have a class that evaluates some computationally intensive function:

class Value
{
private:
  int eval()
  {
    mCached = ExpensiveOperation();
    return mCached;
  }
  static int mCached;
};

Now suppose that Value is actually some template expression, like Plus<1, Multiply<2, 3>> or something to that effect. It may itself be nested and might appear multiple times as part of a larger expression.

I don't know what the expression is, but I do know, based on its position in the expression, which instantiation of it (if there are multiple instantiations of exactly the same type) will be evaluated first.

I want to memoize the result for subsequently instantiated types, such that they are not evaluated more than once each time the expression is evaluated.

The easy way of achieving this is store the cached results in some sort of hash_map or to use singletons which check whether a static member is evaluated, but heap allocation and lookups are expensive, plus we already know the types at compile time and we know which instance is going to be evaluated first, so why not prepare the memoization at compile time as well?

What if we had something like a Cached type, which simply pulled the result from the first class of the same type:

template <typename Expression>
class Cached
{
  int eval()
  {
    return Expression::mCached; // cheap!
  }
};

The problem is that I now have to remember to place Cached everywhere if an expression is repeated!

// Inefficient but nice expression:
Add<Multiply<2, 3>, Multiply<2, 3>>

// Efficient but ugly expression
Add<Multiply<2, 3>, Cached<2, 3>>;

How can I create an expression that looks like the "inefficient but nice expression" yet still automatically generates a Cached type?

2
  • Is the computation result always the same for the same type ? Or may it differ according to some external parameters in each run ? Sep 19, 2014 at 16:50
  • @YochaiTimmer it can differ each run, but in each run it is the same for all instantiations of the same type.
    – quant
    Sep 19, 2014 at 22:01

2 Answers 2

1

If I understood your question correctly, you can just use a local static variable to store the result of the expensive calculation.

class Value
{
private:
  int eval()
  {
    static int mCached = ExpensiveOperation();
    return mCached;
  }
};
1
  • Note that a local static variable is a thread safe singleton (in C++11), so this answer is strictly both simpler and better than the Lazy Singleton solution in 11, in 03 it is still a singleton but no longer thread safe. Sep 27, 2014 at 18:41
0

You can look at the cached value as a Lazy Singleton object.
This way it will only be calculated once per type.

int eval()
  {
    if (mCached == nullptr)
    {
       //Lock here
       if (mCached == nullptr) //double check after lock
       {
          int tempValue = ExpensiveOperation();
          mCached.reset(new int(tempValue));
       }
    }
    return *mCached.get();
  }
static uinque_ptr<int> mCached;
3
  • What is the point of the new?
    – quant
    Sep 19, 2014 at 22:04
  • Double checked locking doesn't work in C++.
    – D Drmmr
    Sep 20, 2014 at 18:15
  • It's just pseudo code. In c++11 you can make it safe. Sep 20, 2014 at 19:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.