2013-05-16 33 views
14

Tôi thường thấy mình viết các hàm tạo di chuyển tẻ nhạt cho các lớp có nhiều biến thành viên. Chúng trông giống như sau:Ủy quyền cho hàm tạo di chuyển mặc định

A(A && rhs) : 
    a(std::move(rhs.a)), 
    b(std::move(rhs.b)), 
    c(std::move(rhs.c)), 
    d(std::move(rhs.d)) { 
    some_extra_work(); 
} 

Tức là, chúng thực hiện tất cả các hành động liên quan đến hàm tạo mặc định, sau đó tạo một số nhiệm vụ thừa. Lý tưởng nhất là tôi sẽ ủy nhiệm cho constructor di chuyển mặc định sau đó thực hiện thêm công việc, tuy nhiên hành động định nghĩa constructor di chuyển của riêng tôi ngăn cản việc thực hiện mặc định không được định nghĩa, nghĩa là không có gì để ủy nhiệm.

Có cách nào tốt đẹp để giải quyết vấn đề chống mẫu này không?

+6

Khó để nói về mức độ trừu tượng như vậy, nhưng có lẽ bạn có thể tách 'A' thành hai lớp và đặt một thành khác? Một sẽ có tất cả các hàm tạo mặc định và một hàm khác sẽ làm 'some_extra_work'. Kiểm tra * Quy tắc không *. – zch

+0

Không chắc chắn nếu điều này được áp dụng, nhưng sẽ giống như 'A (A & & nbsp; rhs, int): A (rhs) {} 'không hoạt động? – Damon

+3

Một lớp cơ sở trung gian với một hàm khởi tạo mặc định có thể hữu ích. –

Trả lời

3

Cập nhật: bỏ qua phần đầu của câu trả lời này và bỏ qua đến cuối có giải pháp tốt hơn.

Bó việc làm thêm trong một loại mới và kế thừa từ nó:

class A; 

struct EW 
{ 
    EW(EW&&); 
}; 

class A : private EW 
{ 
    friend class EW; 
public: 
    A(A&&) = default; 
}; 

EW::EW(EW&&) { A* self = static_cast<A*>(this); self->some_extra_work(); } 

Bạn cũng có thể làm điều đó với một thành viên dữ liệu thay vì một lớp cơ sở, nhưng bạn sẽ cần một số hackery sử dụng offsetof (không được xác định đối với các loại bố cục không theo tiêu chuẩn) hoặc tương đương bằng tay sử dụng số học con trỏ lén lút. Sử dụng thừa kế cho phép bạn sử dụng static_cast để chuyển đổi.

này sẽ không hoạt động nếu some_extra_work() phải được thực hiện sau khi các thành viên được khởi tạo vì lớp cơ sở được khởi động đầu tiên.

Hoặc nếu công việc phụ thực sự hoạt động trên đối tượng rvalue mà bạn đang di chuyển, thì bạn nên bao bọc các thành viên theo các loại hoạt động tự động khi được di chuyển từ, ví dụ: tidy_ptr loại của tôi, mà tôi sử dụng để thực hiện các Rule of Zero

class A 
{ 
    tidy_ptr<D> d; 
public: 
    A() = default; 
    A(const A&) = default; 
    A(A&& r) = default; // Postcondition: r.d == nullptr 
}; 
+0

Tôi tự hỏi, không phải là ctor di chuyển cơ sở lớp gọi * trước khi * các thành viên di chuyển ctors? – Xeo

+0

Nó là có, do đó, sẽ không hoạt động nếu công việc phụ dựa vào các thành viên khác. Khi tôi viết rằng tôi đã không đọc nhận xét của OP nói rằng "ví dụ cổ điển của some_extra_work() đối với tôi là' rhs.d = 0; '" –

+0

... phần thứ hai của câu trả lời hoạt động trong trường hợp đó mặc dù –

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