2011-10-26 31 views
25

Đây có phải là cách hợp lệ để tạo toán tử gán với các thành viên tham chiếu không?Nhà điều hành chuyển nhượng với thành viên tham chiếu

#include <new> 

struct A 
{ 
    int &ref; 
    A(int &Ref) : ref(Ref) { } 
    A(const A &second) : ref(second.ref) { } 
    A &operator =(const A &second) 
    { 
     if(this == &second) 
      return *this; 
     this->~A(); 
     new(this) A(second); 
     return *this; 
    } 
} 

Dường như với biên dịch và chạy tốt, nhưng với C++ xu hướng bề mặt hành vi undefined khi ít mong đợi nhất, và tất cả những người mà nói không thể của mình, tôi nghĩ rằng có một số Gotcha tôi bỏ qua. Tôi đã bỏ lỡ bất cứ điều gì?

+0

Bằng cách này, các đối số cho 'operator =' và các nhà xây dựng bản sao nên tham khảo const. –

+1

Sự chính xác có thể bị hạn chế đối với các kiểu bố trí chuẩn, vì với các virtual 'this' không cần phải là con trỏ tới phần đầu của khối bộ nhớ. –

+6

Nếu bạn cần làm điều này, tôi khuyên bạn nên xem xét lại bằng cách sử dụng tài liệu tham khảo. – bames53

Trả lời

31

Chính xác là cú pháp. Tuy nhiên, nếu vị trí mới ném, bạn kết thúc với một đối tượng mà bạn không thể hủy. Chưa kể đến thảm họa nếu ai đó xuất phát từ lớp học của bạn. Chỉ cần không làm điều đó.

Giải pháp rất đơn giản: nếu lớp cần hỗ trợ chuyển nhượng, đừng sử dụng bất kỳ thành viên tham chiếu nào. Tôi có rất nhiều lớp học tham chiếu đối số, nhưng lưu trữ chúng dưới dạng con trỏ, vì vậy lớp học có thể hỗ trợ chuyển nhượng . Một cái gì đó như:

struct A 
{ 
    int* myRef; 
    A(int& ref) : myRef(&ref) {} 
    // ... 
}; 
+0

+1, đó là những gì tôi làm. –

+0

Tôi thích điều này - giải pháp đơn giản! – aardvarkk

3

Bạn làm gì về mặt kỹ thuật chính xác theo như tôi biết, nhưng nó gây ra sự cố. Ví dụ, hãy xem xét những gì xảy ra với một lớp dẫn xuất từ ​​A, vì toán tử gán của nó tạo ra một đối tượng mới (slicing). Bạn không thể biến tham chiếu thành một con trỏ trong lớp của bạn?

Bên cạnh đó, sao chép các nhà xây dựng và nhà khai thác gán thường lấy đối số của nó bằng const&.

+0

Điều này tạo ra sự cố như thế nào? –

1

Việc bạn làm là chính xác, nhưng cách viết một tác nhân gán bản sao không phải là một cách rất an toàn. Ngoài ra, bạn nên xem xét việc sử dụng một thành viên con trỏ chứ không phải là một thành viên tham khảo.

Bạn nên triển khai nó bằng cách sử dụng Copy and Swap Idiom. Nó có ít nhất 3 lợi thế so với việc thực hiện của bạn.

+0

Nhưng sau đó làm thế nào để trao đổi các tài liệu tham khảo? –

+0

@ChristianRau: Bạn sẽ thực hiện chức năng 'hoán đổi 'của riêng mình. –

+0

Có, và điều này có thể cần phải trao đổi các tài liệu tham khảo. –

2

giải pháp khác là sử dụng lớp reference_wrapper (trong phần đầu chức năng):

struct A 
{ 
    A(int& a) : a_(a) {} 
    A(const A& a) : a_(a.a_) {} 

    A& operator=(const A& a) 
    { 
     a_ = a.a_; 
     return *this; 
    } 

    void inc() const 
    { 
     ++a_; 
    } 

    std::reference_wrapper<int>a_; 

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