我正在阅读Mark Joshi撰写的C ++设计模式和衍生品定价,并在C ++ 11中实现他的代码。在我第4章讨论虚拟拷贝构造函数之前,一切都进行得很顺利。
PayOffDoubleDigital thePayOff(Low, Up);
VanillaOption theOption(thePayOff, Expiry);
此处的问题是VanillaOption
包含对thePayOff
的引用。如果是这种情况并且某人修改了thePayOff
,则theOption
的行为可能会在不知情的情况下被修改。他建议的解决方案是在PayOffDoubleDigital
的基类PayOff
中创建一个虚拟副本构造函数,以便theOption
包含自己的副本:
virtual PayOff* clone() const = 0;
然后在每个继承的类中定义:
PayOff* PayOffCall::clone() const
{
return new PayOffCall(*this);
}
在C ++ 11中,回归新事物可能是不合适的。那么使用C ++ 11处理这个问题的正确方法是什么?
答案 0 :(得分:12)
他建议的解决方案是在PayOffDoubleDigital的基类中创建虚拟副本构造函数[...]
首先,clone()
不是复制构造函数。类X
的复制构造函数是一个特殊的成员函数,没有返回类型,通常具有签名:
X(X const&)
可以签名:
X(X&)
函数clone()
只是一个常规(虚拟)函数,它的特殊含义被你 - 用户认可为创建对象克隆的东西,而不是编译器,它不知道是什么clone()
确实如此。
在C ++ 11中返回新的东西可能是不合适的
的确如此,使用new
在C ++ 11中并不是惯用的。事实上,在C ++ 11中你应该(几乎)永远不会使用new
,除非你正在进行真正的低级内存管理(你应该避免这种情况,除非你真的必须这样做) - 和在C ++ 14中,您可以删除“几乎”。不幸的是,这可能是需要new
的例外情况。
我这样说是因为我相信返回一个unique_ptr
听起来像是在这里做的恰当的事情(选项对象必须拥有自己的PayOff
对象,并且必须保持活着因为选项对象是活着的),并且C ++ 11中没有std::make_unique()
函数(它将在C ++ 14中出现):
std::unique_ptr<PayOff> PayOffCall::clone() const
{
return std::unique_ptr<PayOff>(new PayOffCall(*this));
}
让VanillaOption
(或其基类)持有unique_ptr
而不是原始指针会使delete
PayOff
对象返回clone()
对象变得不必要}。反过来,没有delete
该对象意味着不需要定义用户提供的析构函数,也不需要关注Rule of Three,Rule of Five或其他什么。
只要您可以,请按R. Martinho's Fernandes's advice并转到Rule of Zero。
答案 1 :(得分:0)
通常在处理所有权时,最干净的解决方案是返回一个智能指针:它既保证了异常安全(没有内存泄漏的风险),又清楚地说明对象所属的对象。
您是否要使用unique_ptr
或shared_ptr
完全取决于您。