The short answer: the Handle
class is a smart pointer to pointer.
What is it good for? Take, for example, an instance of an interest-rate index such as Euribor6M
. Right now, its constructor takes a handle to a yield term structure from which it forecasts its future fixings. What would change if we used a shared_ptr
instead?
Let's look at a use case. Warning: I'm simplifying things to avoid writing too much code, but it's a legitimate use case we have. Let's say we initialized the index with a flat curve to begin with:
shared_ptr<SimpleQuote> r = make_shared<SimpleQuote>(0.01);
shared_ptr<YieldTermStructure> curve =
make_shared<FlatForward>(today, r, Actual360());
shared_ptr<InterestRateIndex> index = make_shared<Euribor6M>(curve);
(in a real use case, curve
would be an Euribor curve bootstrapped over a set of quoted rates). The constructor of index
takes a copy of the passed shared_ptr<YieldTermStructure>
and makes a copy of it to store as a data member. After it's built, we'll pass the index to other instruments (swaps, floating-rate bonds, whatever).
In case the interest rate changed, and given we still have a hold of the r
quote, our client code can write
r->setValue(0.015);
Since r
and curve
are shared pointers, this will also change the rate in the copy of the curve inside the index (because both curve
and its copy inside index
point to the same object). As a result, the index fixings and the depending instrument values will also change.
However, let's say we want to start using another curve. In this case, we might want to switch to an interpolated curve instead of a flat one:
vector<Date> dates = ... ;
vector<Rate> rates = ... ;
shared_ptr<YieldTermStructure> curve2 =
make_shared<ZeroCurve>(dates, rates, Actual360());
(in a real case, we might want to bootstrap the curve on a different set of quotes or to use another way to model rates).
How can we tell index
that it should start using curve2
? Using shared_ptr
, we can't. Even if we say:
curve = curve2;
this will cause curve
to point to the interpolated curve, but the copy of curve
inside index
will keep pointing to the old one. This is not a problem with shared_ptr
, but with pointers in general. How do you solve it? By adding another layer of indirection. If you were using raw pointers, you'd start using pointers to pointers. In our code, Handle
does the same thing: it "points" to a shared_ptr
, and is implemented so that two copies of the same handle point to the same shared_ptr. This way, if you write:
shared_ptr<SimpleQuote> r = make_shared<SimpleQuote>(0.01);
shared_ptr<YieldTermStructure> curve =
make_shared<FlatForward>(today, r, Actual360());
RelinkableHandle<YieldTermStructure> h(curve);
shared_ptr<InterestRateIndex> index = make_shared<Euribor6M>(h);
you can later write:
h.linkTo(curve2);
and both the handle you hold and its copy inside index
will point to the new curve.
As for the difference between RelinkableHandle
and Handle
: you can only call linkTo
on the former. The idea is that you instantiate a RelinkableHandle
, pass around copies as just Handle
, and so you ensure that nobody but you can change what it points to (using const
wouldn't work, since constness can be cast away by a simple copy).