2013-05-28 43 views
6

Tôi đang đọc C++ Design Patterns và Derivatives Pricing của Mark Joshi và triển khai mã của mình trong C++ 11. Mọi thứ đã diễn ra khá tốt cho đến khi tôi nhấn chương 4, nơi anh ta thảo luận về các nhà xây dựng bản sao ảo.C++ 11 constructor ảo sao chép

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

Vấn đề ở đây là VanillaOption chứa tham chiếu đến thePayOff. Nếu đó là trường hợp và ai đó sửa đổi thePayOff, hành vi của theOption có thể được sửa đổi vô tình. Giải pháp ông khuyên là để tạo ra một constructor sao chép ảo trong lớp cơ sở PayOffDoubleDigital 's, PayOff để theOption chứa bản sao riêng của nó:

virtual PayOff* clone() const = 0; 

và sau đó được xác định trong mỗi lớp được thừa kế:

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

Trở mới bắt tôi như một cái gì đó có thể không phù hợp trong C++ 11. Vì vậy, cách thích hợp để xử lý này bằng cách sử dụng C++ 11 là gì?

+3

Quy tắc 0: tạo một lớp xử lý với ngữ nghĩa quyền sở hữu thích hợp và sử dụng ở mọi nơi. –

+0

Có vẻ như tôi có một số nghiên cứu bổ sung. Cảm ơn Martinho. – BDig

+0

Tôi đã viết về nó trước đây: http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html –

Trả lời

11

Giải pháp ông khuyên là để tạo ra một constructor sao chép ảo trong lớp cơ sở PayOffDoubleDigital của [...]

Trước hết, clone() không phải là một bản sao-constructor. Một constructor sao chép cho lớp X là một hàm thành viên đặc biệt không có kiểu trả về mà thường có chữ ký:

X(X const&) 

thể có chữ ký:

X(X&) 

Chức năng clone() chỉ là một thường xuyên (ảo), và ý nghĩa đặc biệt của nó được nhận ra bởi bạn - người dùng - như một thứ tạo ra bản sao của đối tượng của bạn, nhưng không phải bởi trình biên dịch, mà không biết clone() là gì.

Trở mới bắt tôi như một cái gì đó mà có thể không phù hợp trong C++ 11

Đó là sự thật, sử dụng new không phải là thành ngữ trong C++ 11. Trong thực tế, trong C++ 11 bạn nên (gần như) không bao giờ sử dụng new trừ khi bạn đang thực sự quản lý bộ nhớ cấp thấp (bạn nên tránh trừ khi bạn thực sự phải) - và trong C++ 14, bạn có thể xóa hầu hết". Thật không may, đây có thể là trường hợp ngoại lệ khi cần new.

Tôi đang nói điều này vì tôi tin rằng sẽ trả về một âm thanh unique_ptr giống như điều thích hợp để làm ở đây (đối tượng tùy chọn phải giữ đối tượng PayOff của riêng nó và phải ở đó miễn là đối tượng tùy chọn còn sống) , và không có std::make_unique() hàm trong C++ 11 (nó sẽ ở đó trong C++ 14):

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

VanillaOption (hoặc lớp cơ sở của nó) tổ chức một unique_ptr chứ không phải là một con trỏ thô sẽ làm cho nó không cần thiết đối với delete đối tượng PayOff được trả lại bởi clone(). Đổi lại, không phải delete đối tượng đó có nghĩa là không cần phải xác định một destructor do người dùng cung cấp, và không cần phải quan tâm đến số Rule of Three, Rule of Five hoặc không có gì.

Bất cứ khi nào bạn có thể, hãy theo dõi R. Martinho's Fernandes's advice và đi tới số Rule of Zero.

+0

Cảm ơn bạn đã trả lời suy nghĩ tốt. Đây là một khu vực của C + + đã được khó khăn để làm chủ cho tôi. Tôi sẽ đánh dấu điều này nếu tôi có thể. Nhưng, đây là câu hỏi đầu tiên của tôi, tôi không có danh tiếng cần thiết. Cần thêm người để đánh dấu câu hỏi :) – BDig

+0

@BDig: Đừng lo lắng, hãy tiếp tục đặt câu hỏi hay và bạn sẽ sớm nhận được đại diện :) Rất vui khi tôi có thể giúp và chúc bạn may mắn với sách của mình –

0

Thường xuyên khi giao dịch với quyền sở hữu, giải pháp sạch nhất là trả lại con trỏ thông minh: đảm bảo an toàn ngoại lệ (không có nguy cơ rò rỉ bộ nhớ) và làm rõ đối tượng sở hữu.

Cho dù bạn sẽ muốn sử dụng unique_ptr hoặc shared_ptr phụ thuộc hoàn toàn vào bạn.

Các vấn đề liên quan