Tôi có thể làm gì với một đối tượng chuyển từ?


138

Tiêu chuẩn có xác định chính xác những gì tôi có thể làm với một đối tượng một khi nó đã được di chuyển từ đó không? Tôi đã từng nghĩ rằng tất cả những gì bạn có thể làm với một đối tượng chuyển từ là phá hủy nó, nhưng điều đó là không đủ.

Ví dụ: lấy mẫu hàm swapnhư được định nghĩa trong thư viện chuẩn:

template <typename T>
void swap(T& a, T& b)
{
    T c = std::move(a); // line 1
    a = std::move(b);   // line 2: assignment to moved-from object!
    b = std::move(c);   // line 3: assignment to moved-from object!
}

Rõ ràng, phải có khả năng gán cho các đối tượng được di chuyển, nếu không các dòng 2 và 3 sẽ thất bại. Vì vậy, tôi có thể làm gì khác với các đối tượng di chuyển? Chính xác thì tôi có thể tìm thấy những chi tiết này trong tiêu chuẩn ở đâu?

(Nhân tiện, tại sao nó lại T c = std::move(a);thay vì T c(std::move(a));trong dòng 1?)

Câu trả lời:


53

Di chuyển từ các đối tượng tồn tại trong một trạng thái không xác định, nhưng hợp lệ. Điều đó cho thấy rằng trong khi đối tượng có thể không còn khả năng làm gì nữa, tất cả các chức năng thành viên của nó vẫn nên thể hiện hành vi được xác định - bao gồm operator=- và tất cả các thành viên của nó ở trạng thái xác định - và nó vẫn cần phải phá hủy. Tiêu chuẩn không đưa ra định nghĩa cụ thể vì nó sẽ là duy nhất cho mỗi UDT, nhưng bạn có thể tìm thấy thông số kỹ thuật cho các loại Tiêu chuẩn. Một số như container tương đối rõ ràng - chúng chỉ di chuyển nội dung của chúng xung quanh và một container rỗng là trạng thái hợp lệ được xác định rõ. Người nguyên thủy không sửa đổi đối tượng chuyển từ.

Lưu ý bên lề: Tôi tin T c = std::move(a)rằng nếu hàm tạo di chuyển (hoặc sao chép hàm tạo nếu không có động thái nào được cung cấp) thì rõ ràng chức năng sẽ thất bại.


26
Không phải tất cả các chức năng thành viên của nó sẽ thể hiện hành vi được xác định. Chỉ những người không có điều kiện tiên quyết. Ví dụ, bạn có thể không muốn pop_backchuyển từ vector. Nhưng bạn chắc chắn có thể tìm ra nếu nó là empty().
Howard Hinnant

6
@Howard Hinnant: pop_backtừ một sản phẩm nào đó vectorcó hành vi không xác định dù sao, từ bộ nhớ, vì vậy tôi khá chắc chắn rằng pop_backtừ một vectơ di chuyển thể hiện hành vi không xác định là phù hợp.
Cún con

12
Chúng ta đang thảo luận về việc di chuyển - từ các đối tượng. Không phải đối tượng được biết là ở trạng thái trống rỗng. Các đối tượng được di chuyển từ trạng thái không xác định (tất nhiên trừ khi có quy định khác). [lib.types.mondfrom]
Howard Hinnant

5
@Howard Không xác định, nhưng hợp lệ, vì vậy pop_backvẫn hoạt động như trên bất kỳ vectơ hợp lệ nào (thậm chí có thể là một vectơ trống).
Christian Rau

1
không xác định và hợp lệ có nghĩa là gì trong bối cảnh này?
Ankur S

114

17.6.5.15 [lib.types.mondfrom]

Các đối tượng của các loại được xác định trong thư viện chuẩn C ++ có thể được di chuyển từ (12.8). Các hoạt động di chuyển có thể được chỉ định rõ ràng hoặc được tạo ngầm. Trừ khi có quy định khác, các đối tượng di chuyển từ đó sẽ được đặt ở trạng thái hợp lệ nhưng không xác định.

Khi một đối tượng ở trạng thái không xác định, bạn có thể thực hiện bất kỳ thao tác nào trên đối tượng không có điều kiện tiên quyết. Nếu có một thao tác với các điều kiện tiên quyết bạn muốn thực hiện, bạn không thể trực tiếp thực hiện thao tác đó vì bạn không biết trạng thái không xác định của đối tượng có thỏa mãn các điều kiện tiên quyết hay không.

Ví dụ về các hoạt động thường không có điều kiện tiên quyết:

  • sự phá hủy
  • phân công
  • quan sát const như get, empty,size

Ví dụ về các hoạt động thường có điều kiện tiên quyết:

  • sự trung thành
  • pop_back

Câu trả lời này hiện xuất hiện ở định dạng video tại đây: http://www.youtube.com/watch?v=vLinb2fgkHk&t=47m10s


1
Nhưng tôi chỉ đơn giản là có thể kiểm tra các điều kiện tiên quyết giống như với bất kỳ đối tượng nào khác, phải không?
dòng chảy

6
@FredOverflow Miễn là bản thân các kiểm tra này không có điều kiện tiên quyết.
Christian Rau

1
@Chris: Nhưng nó khác với một vật thể bình thường, không di chuyển như thế nào?
dòng chảy

2
Có thể là một câu hỏi riêng biệt, nhưng điều đó có nghĩa là: nếu tôi có một chuỗi với char* buffer;int length;các thành viên, thì hàm tạo / chuyển nhượng di chuyển của tôi phải hoán đổi (hoặc đặt) giá trị của cả hai? Hoặc nó sẽ ổn, nếu độ dài không xác định (có nghĩa là emptysizetrả về các giá trị vô nghĩa)?
ChúBens

3
@ 6502: Bạn không có ý nghĩa. Một lớp C ++ 03 không "vi phạm tiêu chuẩn C ++ 0x" bởi vì một ctor di chuyển nếu được tạo sẽ vi phạm tiêu chuẩn. Và mã C ++ 03 sẽ không di chuyển lớp đó vì vậy không có lý do gì để tạo ra một ctor di chuyển.
MSalters
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.