I'm reading C++ Design Patterns and Derivatives Pricing by Mark Joshi and implementing his code in C++11. Everything has gone pretty well until I hit chapter 4 where he discusses virtual copy constructors.
PayOffDoubleDigital thePayOff(Low, Up);
VanillaOption theOption(thePayOff, Expiry);
The problem here is that VanillaOption
contains a reference to thePayOff
. If that's the case and someone modifies thePayOff
, the the behavior of theOption
could be modified unwittingly. The solution he advises is to create a virtual copy constructor in PayOffDoubleDigital
's base class, PayOff
so that theOption
contains its own copy:
virtual PayOff* clone() const = 0;
and then defined in each inherited class:
PayOff* PayOffCall::clone() const
{
return new PayOffCall(*this);
}
Returning new caught me as something that might be inappropriate in C++11. So what is the proper way of handling this using C++11?
The duplicate object being created with the help of Clone() virtual function which is also considered as virtual copy constructor.
In C++, the constructor cannot be virtual, because when a constructor of a class is executed there is no virtual table in the memory, means no virtual pointer defined yet. So, the constructor should always be non-virtual.
In C++ copying the object means cloning. There is no any special cloning in the language. As the standard suggests, after copying you should have 2 identical copies of the same object.
A copy constructor is a special type of constructor that is used to create an object that is an exact copy of the object that is passed. A virtual function is a member function that is declared in the parent class and is redefined ( overridden) in a child class that inherits the parent class.
The solution he advises is to create a virtual copy constructor in PayOffDoubleDigital's base class [...]
First of all, clone()
is not a copy-constructor. A copy constructor for class X
is a special member function with no return type which usually has the signature:
X(X const&)
And may have the signature:
X(X&)
Function clone()
is just a regular (virtual) function, and its particular meaning is recognized by you - the user - as something which creates clones of your object, but not by the compiler, which has no idea what clone()
does.
Returning new caught me as something that might be inappropriate in C++11
That's true, using new
is not idiomatic in C++11. In fact, in C++11 you should (almost) never use new
unless you are doing really low-level memory management (something you should avoid unless you really have to) - and in C++14, you can remove the "almost". Unfortunately, this is likely the exceptional case where new
is needed.
I'm saying this because I believe returning a unique_ptr
sounds like the appropriate thing to do here (the option object has to hold its own PayOff
object, and that must stay alive just as long as the option object is alive), and there is no std::make_unique()
function in C++11 (it will be there in C++14):
std::unique_ptr<PayOff> PayOffCall::clone() const
{
return std::unique_ptr<PayOff>(new PayOffCall(*this));
}
Having VanillaOption
(or its base class) hold a unique_ptr
rather than a raw pointer would make it unnecessary to delete
the PayOff
object returned by clone()
. In turn, not having to delete
that object means no need to define a user-provided destructor, and no need to take care about the Rule of Three, Rule of Five, or whatnot.
Whenever you can, follow R. Martinho's Fernandes's advice and go for the Rule of Zero.
As often when dealing with ownership, the cleanest solution is to return a smart pointer: it both guarantees exception safety (no risk of memory leak) and makes it clear by whom the objects are owned.
Whether you'll want to use unique_ptr
or shared_ptr
depends entirely on you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With