2016-07-29 13 views
15

xem xét lớp này đơn giảnrvalues ​​với bản sao khai thác

class Foo 
{ 
    public: 
    Foo() = default; 
    Foo(const Foo &) = default; 
    Foo & operator=(const Foo & rhs) 
    { 
     return *this; 
    } 
    Foo & operator=(Foo && rhs) = delete; 
}; 

Foo getFoo() 
{ 
    Foo f; 
    return f; 
} 

int main() 
{ 
    Foo f; 
    Foo & rf = f; 
    rf = getFoo(); // Use of deleted move assignment. 
    return 0; 
} 

Khi tôi biên dịch ví dụ trên tôi nhận được error: use of deleted function 'Foo& Foo::operator=(Foo&&)'

Từ Copy Assignment:

Nếu chỉ việc giao bản sao được cung cấp, tất cả các loại đối số chọn nó (miễn là nó lấy đối số của nó theo giá trị hoặc tham chiếu đến const, vì rvalues ​​có thể liên kết với tham chiếu const), làm cho việc gán bản sao dự phòng cho m ove chuyển nhượng, khi di chuyển không có sẵn.

Tại sao trình biên dịch dự phòng không được sao chép khi tham chiếu const lvalue có thể liên kết với rvalue và const Foo & f = getFoo(); hoạt động.

Trình biên dịch - gcc 4.7.2.

Trả lời

10

Không có dự phòng, khái niệm được gọi là độ phân giải quá tải.

Trình biên dịch thực hiện độ phân giải quá tải và đưa ra quyết định trước khi kiểm tra xem phương pháp có bị xóa hay không. Trình biên dịch quyết định rằng hàm tạo di chuyển là lựa chọn tốt nhất, sau đó nó xác định rằng phương thức này đã bị xóa, do đó có lỗi.

Lưu ý 1: delete không thực sự xóa phương thức. Nếu sử dụng delete, phương pháp là được định nghĩa là đã xóa, nhưng vẫn có thể tìm thấy bằng độ phân giải quá tải.

Từ cppreference.com tài liệu (tôi nhấn mạnh):

... độ phân giải quá tải diễn ra đầu tiên, và chương trình chỉ vô hình thành nếu chức năng xóa được chọn.

Trong ví dụ của bạn, các nhà xây dựng di chuyển có sẵn (từ quan điểm giải quyết tình trạng quá tải của xem). Tuy nhiên, nó là được xác định là đã xóa.

Lưu ý 2: Nếu bạn không muốn lớp học của bạn có trình xây dựng di chuyển, chỉ cần không xác định nó. Trình biên dịch sẽ không tạo ra một hàm khởi tạo (move constructor) nếu bạn đã khai báo một trong các thao tác sau: copy constructor, toán tử gán bản sao, di chuyển toán tử gán, hàm hủy.

+0

Bạn không có nghĩa là "hàm tạo di chuyển là * có sẵn *"? – Quentin

+0

@Quentin Bạn nói đúng, cảm ơn bạn! Đã chỉnh sửa. – sergej

8

Trình biên dịch đang thực hiện những gì bạn yêu cầu. Bạn đã xóa toán tử gán di chuyển, cho biết bạn không muốn cho phép gán từ các giá trị. Toán tử gán di chuyển sẽ được tìm thấy trong quá trình phân giải quá tải và vì nó bị xóa, chẩn đoán được phát hành.

Nếu bạn chỉ cần khai báo toán tử gán bản sao, thì toán tử gán nhiệm vụ sẽ không được khai báo ngầm, do đó sẽ không tìm thấy thông qua độ phân giải quá tải và toán tử gán bản sao sẽ được gọi thay thế.

4

Trích dẫn có thể là một chút gây hiểu nhầm.

Nếu nhiệm vụ di chuyển không được khai báo hoàn toàn do chuyển nhượng bản sao được khai báo rõ ràng, thì cuộc gọi có giá trị r sẽ "quay trở lại" về việc chuyển nhượng bản sao.

Nhưng, bạn đã tuyên bố chuyển nhượng một cách rõ ràng và xóa nó đi. Vì vậy, việc kê khai nhiệm vụ di chuyển "có sẵn", và giải quyết một định nghĩa đã xóa.

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