为什么 QuantLib 引入句柄 class?

Why did QuantLib introduce the Handle class?

我检查了这个 slides 但仍然没有得到 :

1) what problem does Handle sovled?

2) what is the benefit to add the Handle class?

从它的源代码中,我也无法得到任何线索:

   template <class Type>
    class Handle {
      protected:
        class Link : public Observable, public Observer {
          public:
            explicit Link(const shared_ptr<Type>& h =
                                         shared_ptr<Type>());
            void linkTo(const shared_ptr<Type>&);
            bool empty() const;
            void update() { notifyObservers(); }
          private:
            shared_ptr<Type> h_;
        };
        boost::shared_ptr<Link<Type> > link_;
      public:
        explicit Handle(const shared_ptr<Type>& h =
                                         shared_ptr<Type>());
        const shared_ptr<Type>& operator->() const;
        const shared_ptr<Type>& operator*() const;
        bool empty() const;
        operator boost::shared_ptr<Observable>() const;
    };

    template <class Type>
    class RelinkableHandle : public Handle<Type> {
      public:
        explicit RelinkableHandle(const shared_ptr<Type>& h =
                                         shared_ptr<Type>());
        void linkTo(const boost::shared_ptr<Type>&);
    };

谁能举个更好的例子?

谢谢。

简短的回答:Handle class 是指向指针的智能指针。

它有什么用?以 Euribor6M 等利率指数为例。现在,它的构造函数处理收益率期限结构,从中预测其未来定价。如果我们改用 shared_ptr 会有什么变化?

让我们来看一个用例。警告:我正在简化事情以避免编写太多代码,但这是我们拥有的合法用例。假设我们用一条平坦的曲线初始化索引:

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);

(在实际用例中,curve 将是 Euribor 曲线 bootstrap 在一组报价上计算)。 index 的构造函数获取传递的 shared_ptr<YieldTermStructure> 的副本,并复制它作为数据成员存储。建立后,我们会将指数传递给其他工具(掉期、浮动利率债券等)。

如果利率发生变化,并且我们仍然持有 r 报价,我们的客户端代码可以编写

r->setValue(0.015);

由于 rcurve 是共享指针,这也会改变索引内曲线副本的速率(因为 curve 及其在 index 指向同一个对象)。因此,指数定价和相关工具的价值也会发生变化。

但是,假设我们要开始使用另一条曲线。在这种情况下,我们可能希望切换到插值曲线而不是平坦曲线:

vector<Date> dates = ... ;
vector<Rate> rates = ... ;
shared_ptr<YieldTermStructure> curve2 =
    make_shared<ZeroCurve>(dates, rates, Actual360());

(在实际情况下,我们可能希望 bootstrap 不同报价集上的曲线或使用另一种方式对利率建模)。

我们如何告诉 index 它应该开始使用 curve2?使用 shared_ptr,我们不能。即使我们说:

curve = curve2;

这会导致curve指向插值曲线,但是index里面的curvecopy会一直指向旧的。这不是 shared_ptr 的问题,而是一般指针的问题。你是怎么解决的?通过添加另一层间接。如果您使用原始指针,您将开始使用指向指针的指针。在我们的代码中,Handle 做同样的事情:它 "points" 到 shared_ptr,并且实现后相同句柄的两个副本指向相同的 shared_ptr。这样,如果你写:

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);

你以后可以写:

h.linkTo(curve2);

您握住的手柄及其在 index 中的副本都将指向新曲线。

至于RelinkableHandleHandle的区别:前者只能调用linkTo。这个想法是你实例化一个 RelinkableHandle,将副本作为 Handle 传递,这样你就可以确保除了你之外没有人可以更改它指向的内容(使用 const 是行不通的,因为 constness 可以通过一个简单的副本来抛弃)。