QuantLib为什么引入了Handle类?

9

我查看了这份幻灯片,但仍然不明白:

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

有人能给一个更好的例子吗?

谢谢。

1个回答

10
简短的回答:Handle类是指向指针的智能指针。
它有什么好处?以利率指数实例如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是基于一组引用利率推导出的欧元区银行间同业拆放利率曲线。构造函数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());

在实际情况下,我们可能希望在不同的行情中引导曲线或使用其他方法来建模利率。(在这种情况下,我们需要改变引导曲线的数据集或采取其他建模方式。)
我们如何告诉index开始使用curve2?使用shared_ptr是不行的。即使我们说:
curve = curve2;

这将导致curve指向插值曲线,但在index内部的curve副本仍然指向旧的曲线。这不是shared_ptr的问题,而是指针在一般情况下存在的问题。如何解决它?通过添加另一层间接性。如果您使用原始指针,则需要开始使用指向指针的指针。在我们的代码中,Handle执行相同的操作:它“指向”一个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可以通过简单的复制来去除)。


非常感谢您的澄清,Luigi! - camino
谢谢您的澄清。关于这个问题,我还有一个问题。类Link是做什么的?我应该如何考虑传递给link构造函数的共享指针h? - user1559897
链接内的shared_ptr是当前指向的对象。Link类在其上添加了可观察性,以便在指向的对象更改时获得通知。 - Luigi Ballabio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接