// 2025-12-05 // Siehe auch: Owned trait objects (boxed trait objects) // https://google.github.io/comprehensive-rust/smart-pointers/trait-objects.html // mit Stack/Heap/Program Diagramm // src/trait_obj.rs use std::mem::size_of_val; use std::rc::{Rc, Weak}; fn print_float(f: f32) { println!("print_float: {f}"); } #[derive(Debug)] struct MyStruct { a: u32, b: u32, c: u32, } fn raw_ptr() { println!("raw_ptr"); let u = 42_u32; let rp: *const u32 = &u; let mut v = 42_u32; let rmp: *mut u32 = &mut v; unsafe { println!("{}", *rp); *rmp = 43; println!("{}", *rmp); } } pub fn run() { // // ==== Raw Pointer (unsafe) raw_ptr(); // // Smart Ptr println!(); let f = 1.44_f32; let rf = &f; println!("{}", f); println!("{}", rf); print_float(f); print_float(*rf); // ==== Box (std::unique_ptr in C++) println!(); let bf = Box::new(3.8_f32); println!("size_of_val(&bf): {}", size_of_val(&bf)); print_float(*bf); let bf2 = bf; print_float(*bf2); // ==== Rc (multiple/shared ownership, like std::shared_ptr in C++) println!(); let rf = Rc::new(MyStruct { a: 0, b: 1, c: 2 }); let rf2 = Rc::clone(&rf); let rf3 = rf.clone(); // geht auch, aber unueblich es so zu schreiben println!("size_of_val(&rf): {}", size_of_val(&rf)); println!("{:?}", rf); println!("Rc::strong_count: {}", Rc::strong_count(&rf)); println!("Rc::strong_count: {}", Rc::strong_count(&rf2)); println!("Rc::weak_count: {}", Rc::weak_count(&rf2)); // ignoriert // print_float(*rf as f32); // Groesse auf dem Stack! println!("1 size_of: {}", std::mem::size_of::>()); // Groesse von MyStruct println!("2 size_of: {}", std::mem::size_of::()); /* Wie gross ist Rc auf dem Heap? Bei Rc wird werden auf dem Heap gespeichert: - strong: Cell - weak: Cell - value: T Aufgabe: Wie sieht das Speicherbild fuer folgenden Code aus? use std::rc::Rc; let vec_var = vec![1.0, 2.0, 3.0]; let foo = Rc::new(vec_var); let a = Rc::clone(&foo); let b = Rc::clone(&foo); */ // ==== Linked List mit Rc, siehe [2] println!("\nLinked List mit Rc"); #[derive(Debug)] struct Node { value: i32, next: Option>, } // A chain of nodes let node1 = Rc::new(Node { value: 1, next: None, }); let node2 = Rc::new(Node { value: 2, next: Some(Rc::clone(&node1)), }); let node3 = Rc::new(Node { value: 3, next: Some(Rc::clone(&node2)), }); // Multiple owners of node2 let another_ref_to_node2 = Rc::clone(&node2); println!("Node 3: {:?}", node3); println!("Another reference to Node 2: {:?}", another_ref_to_node2); // ==== Cell (kein Smart Pointer) // "Cell implements interior mutability by moving values in and out // of the cell... UnsafeCell opts-out of the immutability guarantee // for &T: a shared reference &UnsafeCell may point to data that // is being mutated. This is called “interior mutability”. Cell und RefCell // verwenden intern UnsafeCell. // Bei multithreaded Code wird nicht Cell und RefCell verwendet // sondern Mutex, RwLock, Atomic*. use std::cell::{Cell, RefCell}; let c = Cell::new(12_u32); // c nicht mutierbar, trotzdem kann man Werte hineinschreiben. Alter // Wert wird gedropt. c.set(100); let x = c.get(); println!("\nCell"); println!("{}", x); // ==== RefCell - interne Mutierbarkeit (Smart Pointer) let rc = RefCell::new(42); let mut r = rc.borrow_mut(); *r = 43; println!("{}", r); // let mut p = rc.borrow_mut(); -- panic! -- // ==== Rc> let rcr1 = Rc::new(RefCell::new(100)); let rcr2 = Rc::clone(&rcr1); let mut r = rcr2.borrow_mut(); // let mut r = rcr2.get_mut(); // geht nur wenn rcr2 mut ist *r += 1; println!("{}", r); println!("{}", Rc::strong_count(&rcr1)); println!("size: {}", size_of_val(&rcr1)); // ==== Arc [1] use std::sync::Arc; use std::thread; println!("\nArc"); let shared_data = Arc::new(vec![1, 2, 3]); let thread_data = Arc::clone(&shared_data); let thr = thread::spawn(move || { println!("Data in thread: {:?}", *thread_data); }); thr.join(); println!("Data in main: {:?}", *shared_data); // haeufig wird bei Threads Arc> verwendet. Das entspricht // Rc bei single thread. // ==== rc::Weak [1] println!("\nWeak"); // Weak (schwache Variante von Rc und Arc) [1] // Rc::weak_count, Rc::downgrade(), Rc::upgrade() ... // Weak pointer besitzen das Objekt nicht, sie wirken sich nicht // auf die Lebenszeit des Objekts aus. // Bei multithreaded Code gibt es sync::Weak. #[derive(Debug)] struct Node2 { value: i32, parent: RefCell>, children: RefCell>>, } let leaf = Rc::new(Node2 { value: 3, parent: RefCell::new(Weak::new()), children: RefCell::new(vec![]), }); let branch = Rc::new(Node2 { value: 5, parent: RefCell::new(Weak::new()), children: RefCell::new(vec![Rc::clone(&leaf)]), }); *leaf.parent.borrow_mut() = Rc::downgrade(&branch); println!("{:?}", leaf); // ==== Weak down/upgrade println!("\nWeak down/upgrade"); // Beispiel aus [2] let strong = Rc::new(5); let weak = Rc::downgrade(&strong); // drop(weak); // wuerde weak moven! println!("weak: {:?}", weak); // Ausgabe: weak: (Weak) // try to upgrade the weak reference if let Some(shared) = weak.upgrade() { println!("Data is still alive: {}", shared); } else { println!("Data has been dropped"); } // In [2] ist auch ein Weak-Beispiel mit doppelt verketteter Liste // Deref, MyBox Typ, https://doc.rust-lang.org/book/ch15-02-deref.html // Drop, https://doc.rust-lang.org/book/ch15-03-drop.html } // Lit // [1] https://gencmurat.com/en/posts/smart-pointers-in-rust/ // [2] https://www.freecodecamp.org/news/smart-pointers-in-rust-with-code-examples