2013-05-28 8 views
6

Ich lese C++ Design Patterns und Derivatives Pricing von Mark Joshi und implementieren seinen Code in C++ 11. Alles ist ziemlich gut gelaufen, bis ich Kapitel 4 erlebe, in dem er virtuelle Kopierkonstruktoren diskutiert.C++ 11 virtuelle Kopie Konstruktor

PayOffDoubleDigital thePayOff(Low, Up); 
VanillaOption theOption(thePayOff, Expiry); 

Das Problem hierbei ist, dass VanillaOption einen Verweis auf thePayOff enthält. Wenn das der Fall ist und jemand thePayOff ändert, könnte das Verhalten von theOption unwissentlich geändert werden. Die Lösung rät er ist eine virtuelle Kopie Konstruktor in PayOffDoubleDigital ‚s Basisklasse zu erstellen, PayOff so dass theOption enthält seine eigene Kopie:

virtual PayOff* clone() const = 0; 

und dann in jeder geerbten Klasse definiert:

PayOff* PayOffCall::clone() const 
{ 
    return new PayOffCall(*this); 
} 

Rückkehr new hat mich als etwas erwischt, das in C++ 11 unpassend sein könnte. Also, was ist der richtige Weg, um dies mit C++ 11 zu behandeln?

+3

Regel von Null: Machen Sie eine Handle-Klasse mit der richtigen Besitz Semantik und nutzen Sie das überall. –

+0

Sieht so aus, als hätte ich noch ein paar Nachforschungen angestellt. Danke Martinho. – BDig

+0

Ich schrieb davor: http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html –

Antwort

11

Die Lösung rät er ist eine virtuelle Kopie Konstruktor in PayOffDoubleDigital der Basisklasse zu schaffen [...]

Zunächst einmal clone() keine Kopie-Konstruktor ist. Eine Kopie Konstruktor für Klasse X ist eine spezielle Member-Funktion ohne Rückgabetyp, die in der Regel die Signatur hat:

X(X const&) 

Und kann haben die Unterschrift:

X(X&) 

Funktion clone() ist nur eine ganz normale (virtuelle) Funktion, und seine besondere Bedeutung wird von Ihnen - dem Benutzer - als etwas erkannt, das Klone Ihres Objekts erzeugt, aber nicht durch den Compiler, der keine Ahnung hat, was clone() tut.

neue Rückkehr fing mich als etwas, das ungeeignet sein könnte in C++ 11

das wahr ist, mit new in C++ nicht idiomatischen ist 11. Tatsächlich sollten Sie in C++ 11 (fast) nie new verwenden, es sei denn Sie tun wirklich Low-Level-Speicherverwaltung (etwas, das Sie vermeiden sollten, wenn Sie wirklich müssen) - und in C++ 14 können Sie entfernen das "fast". Leider ist dies der Ausnahmefall, in dem new benötigt wird.

ich dies sagen, weil ich glaube, ein unique_ptr Rückkehr klingt wie das entsprechende, was hier zu tun (die Option Objekt hat ein eigenes PayOff Objekt zu halten, und das muss nur so lange am Leben bleiben, wie die Option Objekt am Leben ist) , und es gibt keine std::make_unique() Funktion in C++ 11 (es wird dort ++ 14 in C):

std::unique_ptr<PayOff> PayOffCall::clone() const 
{ 
    return std::unique_ptr<PayOff>(new PayOffCall(*this)); 
} 

mit VanillaOption (oder seiner Basisklasse) hält ein unique_ptr eher als ein Rohzeiger würde es machen unnötig zu delete das PayOff Objekt zurückgegeben von clone(). Seinerseits bedeutet delete, dass dieses Objekt keine Notwendigkeit für die Definition eines vom Benutzer bereitgestellten Destruktors und keine Notwendigkeit, sich um die Rule of Three, Rule of Five oder was auch immer zu kümmern, bedeutet.

Wann immer Sie können, folgen Sie R. Martinho's Fernandes's advice und gehen Sie für die Rule of Zero.

+0

Vielen Dank für die gut durchdachte Antwort. Dies ist ein Bereich von C++, der für mich schwierig zu meistern war. Ich würde das markieren, wenn ich könnte. Aber da dies meine erste Frage ist, habe ich nicht den nötigen Ruf. Brauchen Sie mehr Leute, um die Frage zu markieren :) – BDig

+0

@BDig: Mach dir keine Sorgen, halten Sie gute Fragen und Sie werden bald die rep :) Froh, ich könnte helfen, und viel Glück mit Ihrem Buch –

0

Wie oft beim Umgang mit Eigentum, ist die sauberste Lösung, einen intelligenten Zeiger zurückzugeben: es garantiert sowohl Ausnahmesicherheit (kein Risiko von Speicherleck) und macht deutlich, von wem die Objekte gehören.

Ob Sie unique_ptr oder shared_ptr verwenden möchten, hängt vollständig von Ihnen ab.