2016-10-13 21 views
13

Ai đó có thể giải thích cho tôi tại sao Rc<> không phải là Copy?Tại sao std :: rc :: Rc <> không sao chép?

Tôi đang viết mã sử dụng nhiều con trỏ được chia sẻ và phải nhập .clone() tất cả thời gian là nhận được trên dây thần kinh của tôi.

Dường như với tôi rằng Rc<> chỉ nên bao gồm một con trỏ, đó là một kích thước cố định, vì vậy loại chính nó phải là Sized và do đó Copy, phải không?

Tôi có thiếu gì đó không?

Trả lời

20

Dường như với tôi rằng Rc<> chỉ nên bao gồm một con trỏ, mà là một kích thước cố định, vì vậy các loại bản thân nên Sized và do đó Copy, phải không?

Điều này không đúng. Rc là viết tắt của R eference C được tính. Điều này có nghĩa là loại theo dõi số lượng tham chiếu trỏ đến dữ liệu được sở hữu. Bằng cách đó chúng ta có thể có nhiều chủ sở hữu cùng một lúc và an toàn giải phóng dữ liệu, một khi tính tham khảo đạt 0.


Nhưng làm thế nào để chúng tôi giữ bộ đếm tham chiếu hợp lệ và cập nhật? Chính xác, chúng ta phải làm điều gì đó bất cứ khi nào một tham chiếu/chủ sở hữu mới được tạo và bất cứ khi nào một tham chiếu/chủ sở hữu bị xóa. Cụ thể, chúng tôi phải tăng số lượt truy cập trong trường hợp cũ và giảm số lượt truy cập trong trường hợp sau.

Bộ đếm được giảm bằng cách thực hiện Drop, tương đương với Rust của trình phá hủy. Hàm drop() này được thực hiện bất cứ khi nào một biến nằm ngoài phạm vi - hoàn hảo cho mục tiêu của chúng tôi.

Nhưng khi nào chúng tôi thực hiện gia tăng? Bạn đoán nó: trong clone(). The Copy trait, được định nghĩa, nói rằng một loại có thể được nhân đôi chỉ bằng cách sao chép các bit:

Các loại có thể được sao chép bằng cách chỉ cần sao chép các bit (tức là memcpy).

Điều này không đúng trong trường hợp của chúng tôi, bởi vì: có, chúng tôi "chỉ sao chép bit", nhưng chúng tôi cũng thực hiện thêm công việc! Chúng tôi cần tăng số lượt truy cập tham khảo!

4

Một loại không thể thực hiện Copy nếu nó thực hiện Drop (source). Kể từ Rcdoes implement it để giảm số lượng tham chiếu của nó, điều đó là không thể.

Ngoài ra, Rc không chỉ là con trỏ.Nó bao gồm một Shared:

pub struct Rc<T: ?Sized> { 
    ptr: Shared<RcBox<T>>, 
} 

Trong đó, đến lượt nó, không chỉ là một con trỏ:

pub struct Shared<T: ?Sized> { 
    pointer: NonZero<*const T>, 
    _marker: PhantomData<T>, 
} 

PhantomData là cần thiết để thể hiện quyền sở hữu của T:

đánh dấu này có không có hậu quả đối với phương sai, nhưng cần thiết cho số tài khoản để hiểu rằng chúng tôi sở hữu một cách hợp lý một số T.

Để biết chi tiết, xem: https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data

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