C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

Rust のメモリーコンテナー的な何かをわかりやすく整理したチートシートのメモ; T, Cell, RefCell, AtomicT, Mutex, RwLock, Rc, Arc

f:id:USAGI-WRP:20200822033323p:plain

作ったので GitHub ↑ しつつ、なんとなくすごい久しぶりに Qiita に初心者さんに優しそうな雰囲気を装った解説↓

も書いてみました。ちなみに reddit

にもポストしてみました。 reddit はとても参考になる議論がおおむね建設的にものすごい勢いで発生してくれるので嬉しいです。チートシートとしての意図と図面の都合による nitpick たちは README に注釈を付けるといいかなと思います。Allocationからの線の見直しなど a better なシートの提案はうまく取り込んで、できるだけウソの無い、でもチートシートの意図としてはわかりやすさを維持した調整をしたいと思います。

と、それだけ書いたのではわざわざブログにメモを残す理由が薄いので、ここには C++ と Rust でチートシートに掲載したメモリーコンテナー的なそれの大雑把なコードを、翻訳が通るソースとして書き残してみます。

おまけ: C++ の &≈ptr と (mutable)/const 系、Rust の &≈ptr と mut/const 系

// C++
#include <memory>
#include <shared_mutex>
#include <vector>
#include <iostream>
int main()
{
 using T = int; using V = std::vector<T>;
 
 // mutable value
 T valm = 1;
  
 // const ref -> mutable value
 T& refc_valm = valm; refc_valm = 10;
 // const ref -> const value
 T const& refc_valc = valm; std::clog << refc_valc << " <- It's read only.\n";

 // mutable ptr -> mutable value
 T* ptrm_valm = &valm; *ptrm_valm = 11;
 // const ptr -> mutable value
 T* const ptrc_valm = &valm; *ptrc_valm = 21;
 // const ptr -> const value
 const T* const ptrc_valc = &valm; std::clog << *ptrc_valc << " <- It's read only.\n";

 // heap, ≈ 'static lifetime of Rust
 T* ptrm_heap_static_lifetime = new int(-1);

 // heap, ≈ mut Box<T> of Rust
 std::unique_ptr<T> ptrm_heap_single_owner_valm = std::make_unique<T>(-1);
 *ptrm_heap_single_owner_valm = -100;
 // heap, ≈ Box<T> of Rust
 std::unique_ptr<const T> ptrm_heap_single_owner_valc = std::make_unique<T>(-1);

 // heap, ≈ Rc<T> of Rust
 std::shared_ptr<const T> ptrm_heap_multiple_owner_thread_unsafe_valc = std::make_shared<T>(-1);
 // heap, ≈ Rc<Cell<T>> of Rust
 std::shared_ptr<T> ptrm_heap_multiple_owner_thread_unsafe_valm = std::make_shared<T>(-1);
 // heap, ≈ Rc<RefCell<V>> of Rust
 std::shared_ptr<V> ptrm_heap_multiple_owner_thread_unsafe_refm = std::make_shared<V>(V());
 ptrm_heap_multiple_owner_thread_unsafe_refm->push_back(-2000);

 // single reader/writer control object, ≈ Mutex<T> without <T> of Rust
 std::mutex mutex_1rw_thread_safe_controller;
  
 // multiple reader/single writer control object, ≈ RwLock<T> without <T> of Rust
 std::shared_mutex mutex_mr1w_thread_safe_controller;
}
// Rust; Rc:=Reference Counted, Arc:=Automatically Reference Counted
use std::
{ rc::Rc
, sync::{Arc, Mutex, RwLock}
, cell::{ Cell, RefCell }
};
fn main() {
 type T = i32; type V = Vec<T>;
 
 // mutable value
 let mut valm: T = 1;
 let mut valm_the_other = 2;
 
 // const ref -> mutable value
 let refc_valm: &mut T = &mut valm; *refc_valm = 11;
 // const ptr -> const value
 let refc_valc: &T = &valm; println!("{} <-- It's a const value via const ref.", refc_valc);
 
 // mutable ptr -> mutable value; deref-ptr is an unsafe operation
 let mut ptrm_valm: *mut T = &mut valm as *mut T; unsafe { *ptrm_valm = 21 };
 ptrm_valm = &mut valm_the_other as &mut T; unsafe { *ptrm_valm = 22 };
 // const ptr -> mutable value
 let ptrc_valm: *mut T = &mut valm as *mut i32; unsafe { *ptrc_valm = 31 };
 // const ptr -> const value
 let ptrc_valc: *const T = &valm as *const i32; println!("{:?} <-- It's a const value via const ptr.", ptrc_valc);
 
 // heap, ≈ new of C++
 let mut ptrm_heap_static_lifetime: *mut T = unsafe{ std::alloc::alloc( std::alloc::Layout::new::<T>() ) } as *mut T;
 unsafe { *ptrm_heap_static_lifetime = -10 };
 
 // heap, ≈ std::unique_ptr<T> of C++, deref -> mutable value
 let mut ptrm_heap_single_owner_valm: Box<T> = Box::<T>::new(-1);
 *ptrm_heap_single_owner_valm = -100;
 // heap, ≈ std::unique_ptr<const T> of C++, deref -> mutable value
 let ptrm_heap_single_owner_valc: Box<T> = Box::<T>::new(-1);
 
 // heap, ≈ std::shared_ptr<const T> of C++, deref -> const value
 let ptrm_heap_multiple_owner_thread_unsafe_valc: Rc<T> = Rc::<T>::new(-1);
 // heap, ≈ std::shared_ptr<T> + std::mutex of C++, deref -> mutable value
 let ptrm_heap_multiple_owner_thread_unsafe_valm: Rc<Cell<T>> = Rc::new(Cell::<T>::new(-1));
 ptrm_heap_multiple_owner_thread_unsafe_valm.set( -200 );
 // heap, ≈ std::shared_ptr<T> + std::mutex of C++, deref -> mutable ref
 let ptrm_heap_multiple_owner_thread_unsafe_refm: Rc<RefCell<V>> = Rc::new(RefCell::new(V::new()));
 ptrm_heap_multiple_owner_thread_unsafe_refm.borrow_mut().push( -2000 );
 
 // heap, ≈ std::shared_ptr<const T> of C++, deref -> const value
 let ptrm_heap_multiple_owner_thread_unsafe_valc: Arc<T> = Arc::<T>::new(-1);
 // heap, ≈ std::shared_ptr<T> + std::shared_mutex of C++, deref -> mutable value
 let ptrm_heap_multiple_owner_thread_unsafe_valm: Arc<Mutex<T>> = Arc::new(Mutex::<T>::new(-1));
 *ptrm_heap_multiple_owner_thread_unsafe_valm.lock().unwrap() = -200;
 // heap, ≈ std::shared_ptr<T> + std::shared_mutex of C++, deref -> mutable ref
 let ptrm_heap_multiple_owner_thread_unsafe_refm: Arc<RwLock<T>> = Arc::new(RwLock::<T>::new(-1));
 {
   let r0 = *ptrm_heap_multiple_owner_thread_unsafe_refm.read().unwrap();
   let r1 = *ptrm_heap_multiple_owner_thread_unsafe_refm.read().unwrap();
   println!("r0 = {:?}, r1 = {:?}", r0, r1);
   // drop(≈release) r0, r1 then it will be writable in the out of this scope
 }
 *ptrm_heap_multiple_owner_thread_unsafe_refm.write().unwrap() = -3000;
}

参考