为什么 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);
由于 r
和 curve
是共享指针,这也会改变索引内曲线副本的速率(因为 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
里面的curve
的copy会一直指向旧的。这不是 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
中的副本都将指向新曲线。
至于RelinkableHandle
和Handle
的区别:前者只能调用linkTo
。这个想法是你实例化一个 RelinkableHandle
,将副本作为 Handle
传递,这样你就可以确保除了你之外没有人可以更改它指向的内容(使用 const
是行不通的,因为 constness 可以通过一个简单的副本来抛弃)。
我检查了这个 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);
由于 r
和 curve
是共享指针,这也会改变索引内曲线副本的速率(因为 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
里面的curve
的copy会一直指向旧的。这不是 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
中的副本都将指向新曲线。
至于RelinkableHandle
和Handle
的区别:前者只能调用linkTo
。这个想法是你实例化一个 RelinkableHandle
,将副本作为 Handle
传递,这样你就可以确保除了你之外没有人可以更改它指向的内容(使用 const
是行不通的,因为 constness 可以通过一个简单的副本来抛弃)。