RAII
RAII是 Resource Acquisition Is Initialization
的缩写, 最初来自于 C++.
一句话概括就是, 将资源(包括堆内存, 文件句柄, socket, 锁, 数据库连接等等)的管理与对象的生命周期绑定.
利用在栈上创建的局部变量的自动析构来保证它管理的资源一定被释放.
标准库中的 File 类
#![allow(unused)] fn main() { //! Redefinition of `File` struct #![allow(dead_code)] use crate::file_desc::FileDesc; /// An object providing access to an open file on the filesystem. /// /// An instance of a `File` can be read and/or written depending on what options /// it was opened with. Files also implement `Seek` to alter the logical cursor /// that the file contains internally. /// /// Files are automatically closed when they go out of scope. Errors detected /// on closing are ignored by the implementation of `Drop`. Use the method /// `sync_all` if these errors must be manually handled. pub struct File(FileDesc); }
标准库中的 TcpStream 类
#![allow(unused)] fn main() { //! Redefinition of `TcpStream` #![allow(clippy::module_name_repetitions)] #![allow(dead_code)] use crate::file_desc::FileDesc; /// A TCP stream between a local and a remote socket. /// /// After creating a `TcpStream` by either `connect`ing to a remote host or /// `accept`ing a connection on a `TcpListener`, data can be transmitted /// by reading and writing to it. /// /// The connection will be closed when the value is dropped. The reading and writing /// portions of the connection can also be shut down individually with the `shutdown` /// method. pub struct TcpStream { inner: Socket, } pub(crate) struct Socket(FileDesc); }
标准库中的 Mutex 和 MutexGuard 类
#![allow(unused)] fn main() { //! Redefinition of MutexGuard /// A mutual exclusion primitive useful for protecting shared data /// /// This mutex will block threads waiting for the lock to become available. The /// mutex can be created via a [`new`] constructor. Each mutex has a type parameter /// which represents the data that it is protecting. The data can only be accessed /// through the RAII guards returned from [`lock`] and [`try_lock`], which /// guarantees that the data is only ever accessed when the mutex is locked. pub struct Mutex<T: ?Sized> { inner: sys::Mutex, poison: poison::Flag, data: UnsafeCell<T>, } /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. /// /// The data protected by the mutex can be accessed through this guard via its /// [`Deref`] and [`DerefMut`] implementations. /// /// This structure is created by the [`lock`] and [`try_lock`] methods on /// [`Mutex`]. pub struct MutexGuard<'a, T: ?Sized + 'a> { lock: &'a Mutex<T>, poison: poison::Guard, } impl<T: ?Sized> Drop for MutexGuard<'_, T> { #[inline] fn drop(&mut self) { unsafe { self.lock.poison.done(&self.poison); self.lock.inner.unlock(); } } } impl<T: ?Sized> Mutex<T> { /// Acquires a mutex, blocking the current thread until it is able to do so. /// /// This function will block the local thread until it is available to acquire /// the mutex. Upon returning, the thread is the only thread with the lock /// held. An RAII guard is returned to allow scoped unlock of the lock. When /// the guard goes out of scope, the mutex will be unlocked. /// /// The exact behavior on locking a mutex in the thread which already holds /// the lock is left unspecified. However, this function will not return on /// the second call (it might panic or deadlock, for example). pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> { unsafe { self.inner.lock(); MutexGuard::new(self) } } /// Attempts to acquire this lock. /// /// If the lock could not be acquired at this time, then [`Err`] is returned. /// Otherwise, an RAII guard is returned. The lock will be unlocked when the /// guard is dropped. /// /// This function does not block. /// /// # Errors /// /// If another user of this mutex panicked while holding the mutex, then /// this call will return the [`Poisoned`] error if the mutex would /// otherwise be acquired. /// /// If the mutex could not be acquired because it is already locked, then /// this call will return the [`WouldBlock`] error. pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> { unsafe { if self.inner.try_lock() { Ok(MutexGuard::new(self)?) } else { Err(TryLockError::WouldBlock) } } } /// Immediately drops the guard, and consequently unlocks the mutex. /// /// This function is equivalent to calling [`drop`] on the guard but is more self-documenting. /// Alternately, the guard will be automatically dropped when it goes out of scope. pub fn unlock(guard: MutexGuard<'_, T>) { drop(guard); } } }
标准库中的 Box 类
#![allow(unused)] fn main() { use core::ptr::{self, NonNull, Unique}; /// A pointer type that uniquely owns a heap allocation of type `T`. pub struct Box< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, >(Unique<T>, A); impl<T> Box<T> { /// Allocates memory on the heap and then places `x` into it. /// /// This doesn't actually allocate if `T` is zero-sized. #[inline(always)] #[must_use] pub fn new(x: T) -> Self { #[rustc_box] Box::new(x) } } unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> { #[inline] fn drop(&mut self) { // the T in the Box is dropped by the compiler before the destructor is run let ptr = self.0; unsafe { let layout = Layout::for_value_raw(ptr.as_ptr()); if layout.size() != 0 { self.1.deallocate(From::from(ptr.cast()), layout); } } } } }
标准库中的 Rc 类
#![allow(unused)] fn main() { //! Refinition of Rc //! //! Single-threaded reference-counting pointers. 'Rc' stands for 'Reference //! Counted'. //! The type [`Rc<T>`][`Rc`] provides shared ownership of a value of type `T`, //! allocated in the heap. Invoking [`clone`][clone] on [`Rc`] produces a new //! pointer to the same allocation in the heap. When the last [`Rc`] pointer to a //! given allocation is destroyed, the value stored in that allocation (often //! referred to as "inner value") is also dropped. use std::cell::Cell; /// A single-threaded reference-counting pointer. 'Rc' stands for 'Reference /// Counted'. pub struct Rc< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { ptr: NonNull<RcBox<T>>, phantom: PhantomData<RcBox<T>>, alloc: A, } // This is repr(C) to future-proof against possible field-reordering, which // would interfere with otherwise safe [into|from]_raw() of transmutable // inner types. #[repr(C)] struct RcBox<T: ?Sized> { strong: Cell<usize>, weak: Cell<usize>, value: T, } impl<T: ?Sized, A: Allocator> !Send for Rc<T, A> {} impl<T: ?Sized, A: Allocator> !Sync for Rc<T, A> {} impl<T> Rc<T> { /// Constructs a new `Rc<T>`. pub fn new(value: T) -> Rc<T> { // There is an implicit weak pointer owned by all the strong // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. unsafe { Self::from_inner( Box::leak(Box::new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value, })) .into(), ) } } } unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc<T, A> { /// Drops the `Rc`. /// /// This will decrement the strong reference count. If the strong reference /// count reaches zero then the only other references (if any) are /// [`Weak`], so we `drop` the inner value. fn drop(&mut self) { unsafe { self.inner().dec_strong(); if self.inner().strong() == 0 { // destroy the contained object ptr::drop_in_place(Self::get_mut_unchecked(self)); // remove the implicit "strong weak" pointer now that we've // destroyed the contents. self.inner().dec_weak(); if self.inner().weak() == 0 { self.alloc .deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } } } }