# Rust smart pointers uitgelegd: Box, Rc, Arc en RefCell in 2026 > Rust smart pointers Box, Rc, Arc en RefCell uitgelegd met compileerbare 2026-voorbeelden, een beslistabel en veelvoorkomende sollicitatievragen. - Published: 2026-07-05 - Updated: 2026-07-07 - Author: SharpSkill - Tags: rust, smart-pointers, memory-management, interview, rust-2024-edition - Reading time: 11 min --- Rust smart pointers zijn de gereedschappen die ownership-patronen ontsluiten die de borrow checker alleen niet kan uitdrukken: heap-allocatie, gedeeld eigenaarschap en mutatie achter een gedeelde referentie. Waar een gewone referentie (`&T`) een waarde alleen leent, bezit een smart pointer zijn eigen data en legt daar extra gedrag bovenop. Deze gids ontleedt de vier types die elke Rust-ontwikkelaar in productie en in sollicitatiegesprekken tegenkomt: `Box`, `Rc`, `Arc` en `RefCell`, met compileerbare voorbeelden voor de Rust 2024-editie. > **De samenvatting in één regel** > > `Box` is voor heap-allocatie met één eigenaar, `Rc` voor gedeeld eigenaarschap op één thread, `Arc` voor gedeeld eigenaarschap over threads heen en `RefCell` om een waarde via een gedeelde referentie te muteren. De paren `Rc>` en `Arc>` dekken gedeelde muteerbare toestand af. ## Wat smart pointers in Rust zijn Een smart pointer is een struct die zich gedraagt als een pointer, maar extra metadata of mogelijkheden meedraagt. De meeste implementeren de `Deref`-trait, zodat `*pointer` en methodeaanroepen werken alsof de pointer een gewone referentie is, en de `Drop`-trait, zodat het opruimen automatisch gebeurt wanneer de waarde buiten scope raakt. De standaardbibliotheek levert de vier hier behandelde types, en het begrijpen ervan hangt af van een goede beheersing van [ownership en borrowing](/blog/rust/ownership-borrowing-rust-complete-guide), dat bepaalt wie elke allocatie vrijgeeft en wanneer. Het belangrijkste verschil met een referentie is eigenaarschap. `&T` bezit nooit de data waarnaar het wijst en kan de waarde dus niet overleven. Een smart pointer bezit de data, bepaalt de levensduur ervan en geeft die deterministisch vrij. Het [hoofdstuk over smart pointers in het Rust Book](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html) behandelt ze juist als één categorie omdat ze deze vorm van eigenaarschap plus gedrag delen. ## `Box`: heap-allocatie voor recursieve en gedimensioneerde types `Box` is de eenvoudigste smart pointer. Het slaat een waarde op de heap op en houdt er op de stack een pointer naartoe, met één eigenaar en zonder runtime-overhead behalve de allocatie zelf. Zijn meest voorkomende taak is recursieve types een bekende grootte geven: een type dat zichzelf direct bevat zou oneindig groot zijn, maar een `Box` is slechts een pointer, dus de grootte staat vast, ongeacht waarnaar het wijst. Het onderstaande voorbeeld definieert een binaire boom. Elke `Node` bevat twee kinderen, en zonder indirectie kan de compiler de grootte van `Tree` niet berekenen. Elk kind in een `Box` verpakken doorbreekt de recursie op typeniveau. ```rust // tree.rs #[derive(Debug)] enum Tree { Leaf(i32), // Box puts each child on the heap, so Node has a fixed size (two pointers). Node(Box, Box), } fn sum(tree: &Tree) -> i32 { match tree { Tree::Leaf(value) => *value, // base case: return the leaf Tree::Node(left, right) => sum(left) + sum(right), // recurse into both children } } fn main() { // Build (1) + ((2) + (3)) = 6 let tree = Tree::Node( Box::new(Tree::Leaf(1)), Box::new(Tree::Node( Box::new(Tree::Leaf(2)), Box::new(Tree::Leaf(3)), )), ); println!("sum = {}", sum(&tree)); // sum = 6 } ``` `Box` is ook belangrijk wanneer het verplaatsen van een grote waarde duur zou zijn, of wanneer een trait-object zoals `Box` wordt teruggegeven. In elk geval geldt dezelfde regel: één eigenaar, automatisch vrijgegeven wanneer de `Box` wordt opgeruimd. ## `Rc`: gedeeld eigenaarschap in single-threaded code Soms heeft een waarde meerdere eigenaren nodig, waarvan er geen duidelijk de laatste is die hem gebruikt. `Rc` (reference counted) lost dit op door een strong count bij te houden van hoeveel eigenaren er bestaan. `Rc::clone` verhoogt die teller zonder de onderliggende data te kopiëren, en elke drop verlaagt hem. Zodra de teller nul bereikt, wordt de waarde vrijgegeven. Neem een configuratieobject dat meerdere workers lezen. Elke worker moet de configuratie zo lang vasthouden als nodig, en de allocatie moet pas verdwijnen wanneer de laatste worker weg is. ```rust // shared_config.rs use std::rc::Rc; #[derive(Debug)] struct Config { endpoint: String, timeout_ms: u32, } fn main() { // Rc::new moves Config onto the heap with a strong count of 1. let config = Rc::new(Config { endpoint: "https://api.example.com".to_string(), timeout_ms: 5000, }); // Rc::clone only bumps the reference count; it does not deep-copy Config. let worker_a = Rc::clone(&config); let worker_b = Rc::clone(&config); // All three handles point to the same allocation. println!("endpoint: {}", worker_a.endpoint); println!("timeout: {}", worker_b.timeout_ms); // strong_count reports how many owners currently hold the value. println!("owners: {}", Rc::strong_count(&config)); // owners: 3 } ``` `Rc::clone` expliciet aanroepen (in plaats van `config.clone()`) is idiomatisch: het maakt lezers duidelijk dat de operatie goedkoop is en alleen een teller raakt. Het addertje is dat `Rc` uitsluitend gedeelde, onveranderlijke referenties uitgeeft. Het kan de gedeelde waarde niet muteren en is niet veilig om tussen threads te versturen. De [`Rc`-documentatie](https://doc.rust-lang.org/std/rc/struct.Rc.html) beschrijft beide beperkingen. ## `RefCell` en interior mutability in Rust Rust dwingt normaal af dat een waarde ofwel via veel onveranderlijke referenties wordt gedeeld, ofwel via precies één veranderlijke referentie wordt gemuteerd, en controleert dit tijdens het compileren. `RefCell` biedt interior mutability: het laat code een waarde via een gedeelde referentie muteren door diezelfde controle naar runtime te verplaatsen. `borrow()` geeft een gedeelde lees-guard terug; `borrow_mut()` geeft een exclusieve schrijf-guard terug. De regels zijn identiek, maar overtredingen veroorzaken een panic in plaats van een mislukte compilatie. Gecombineerd met `Rc` levert dit het canonieke single-threaded patroon voor gedeelde muteerbare toestand op, `Rc>`: meerdere eigenaren die allemaal dezelfde waarde kunnen bijwerken. ```rust // counter.rs use std::rc::Rc; use std::cell::RefCell; // Rc gives shared ownership; RefCell allows mutation through a shared reference. type SharedCounter = Rc>; fn increment(counter: &SharedCounter) { // borrow_mut() hands out an exclusive reference, checked at runtime. *counter.borrow_mut() += 1; } fn main() { let counter: SharedCounter = Rc::new(RefCell::new(0)); let handle_a = Rc::clone(&counter); let handle_b = Rc::clone(&counter); increment(&handle_a); increment(&handle_b); increment(&counter); // borrow() gives a shared read guard; the value is now 3. println!("count = {}", counter.borrow()); // count = 3 } ``` > **RefCell verplaatst de borrow-controle naar runtime** > > `borrow_mut()` aanroepen terwijl een andere `borrow()`- of `borrow_mut()`-guard nog leeft, veroorzaakt een panic met `already borrowed: BorrowMutError`. De veiligheidsgaranties blijven overeind, maar een logische fout die de compiler had onderschept, wordt een crash tijdens runtime. Houd guards kortlevend en vermijd het vasthouden van een borrow over een functieaanroep die dezelfde `RefCell` opnieuw zou kunnen betreden. Interior mutability is ook de plek waar referentiecycli zich verschuilen. Twee `Rc>`-waarden die naar elkaar wijzen, houden elkaars strong count voor altijd boven nul, zodat geen van beide ooit wordt vrijgegeven. De oplossing is `Weak`, een niet-bezittende handle die de strong count niet beïnvloedt; de klassieke uitleg staat in [Learn Rust With Entirely Too Many Linked Lists](https://rust-unofficial.github.io/too-many-lists/). ## `Arc`: thread-safe reference counting voor concurrency `Arc` (atomically reference counted) is de multi-threaded tegenhanger van `Rc`. De publieke API is vrijwel identiek, maar de teller gebruikt atomaire operaties, zodat het klonen en droppen van een `Arc` vanuit meerdere threads tegelijk correct blijft. Die atomiciteit is de reden waarom `Arc` alleen wordt gekozen wanneer het delen een threadgrens overschrijdt: de atomaire verhoging is meetbaar trager dan de gewone die `Rc` gebruikt. Omdat `Arc` nog steeds onveranderlijke referenties uitgeeft, vereist mutatie over threads heen een synchronisatieprimitief. `Mutex` is de gebruikelijke partner en levert het patroon `Arc>`, dat `Rc>` weerspiegelt voor concurrente code. Het voorbeeld start vier threads die elk een gedeeld totaal duizend keer ophogen. ```rust // parallel_sum.rs use std::sync::{Arc, Mutex}; use std::thread; fn main() { // Arc is safe to share across threads; Mutex serializes access to the inner value. let total = Arc::new(Mutex::new(0u64)); let mut handles = Vec::new(); for _ in 0..4 { // Each thread gets its own Arc handle (an atomic count bump). let total = Arc::clone(&total); handles.push(thread::spawn(move || { for _ in 0..1000 { // lock() blocks until the mutex is free, then returns a guard. let mut value = total.lock().unwrap(); *value += 1; } })); } for handle in handles { handle.join().unwrap(); // wait for every thread before reading } println!("total = {}", *total.lock().unwrap()); // total = 4000 } ``` De compiler dwingt de grens vanzelf af: `Rc` is niet `Send`, dus een poging om er een in `thread::spawn` te verplaatsen, compileert niet en stuurt richting `Arc`. Naar `Arc` grijpen binnen één thread betaalt alleen voor atomaire operaties die nooit worden gebruikt. De [`Arc`-documentatie](https://doc.rust-lang.org/std/sync/struct.Arc.html) behandelt de garanties rond geheugenordening in detail, en `Arc>` draagt een groot deel van de gedeelde toestand in [asynchroon Rust met Tokio](/blog/rust/rust-async-await-tokio-futures-concurrency). ## Box vs Rc vs Arc vs RefCell: wanneer welke gebruiken De vier types stellen zich samen langs twee assen: hoeveel eigenaren een waarde heeft en of hij via een gedeelde handle gemuteerd kan worden. De tabel vat de afwegingen samen. | Type | Eigenaarschap | Mutatie via gedeelde handle | Thread-safe | Overhead | |------|-----------|----------------------------|-------------|----------| | `Box` | Enkel | Nee | Ja, als `T: Send` | Alleen heap-allocatie | | `Rc` | Gedeeld | Nee | Nee | Niet-atomaire teller | | `Arc` | Gedeeld | Nee | Ja | Atomaire teller | | `RefCell` | Enkel | Ja (runtime-gecontroleerd) | Nee | Runtime borrow-vlag | De praktische beslisboom is kort. Eén eigenaar op de heap nodig: `Box`. Meerdere eigenaren op één thread nodig: `Rc`. Meerdere eigenaren over threads heen nodig: `Arc`. Een gedeelde waarde muteren nodig: verpak het binnenste type in `RefCell` (single-thread) of `Mutex` (multi-thread). De richtlijn van Effective Rust over [referentie- en pointertypes](https://www.lurklurk.org/effective-rust/) komt tot dezelfde gelaagdheid. Begin met de minst krachtige optie en voeg pas mogelijkheden toe wanneer de compiler daartoe dwingt. ## Rust smart pointers: sollicitatievragen Smart pointers zijn een betrouwbaar sollicitatieonderwerp omdat ze toetsen of een kandidaat ownership begrijpt in plaats van alleen syntaxis. De onderstaande vragen komen vaak voor, en meer zijn verzameld in de [interviewmodule over Rust smart pointers](/technologies/rust/interview-questions/smart-pointers). **Wat is het verschil tussen `Rc` en `Arc`?** Beide bieden gedeeld eigenaarschap via reference counting. `Rc` gebruikt een niet-atomaire teller en is beperkt tot één thread; `Arc` gebruikt atomaire operaties en kan tegen kleine runtime-kosten over threads worden gedeeld. De compiler dwingt de scheiding af: `Rc` is noch `Send` noch `Sync` en kan dus geen threadgrens overschrijden. **Waarom `Rc` met `RefCell` combineren?** `Rc` verleent gedeeld eigenaarschap maar alleen onveranderlijke toegang. `RefCell` voegt interior mutability toe, waardoor eigenaren de waarde via een gedeelde referentie kunnen muteren met runtime borrow-controles. Samen is `Rc>` de idiomatische single-threaded bouwsteen voor gedeelde muteerbare toestand. **Hoe kan reference counting geheugen lekken in Rust?** Twee `Rc`- (of `Arc`-)waarden die naar elkaar verwijzen, vormen een cyclus waarvan de strong counts nooit nul bereiken, zodat de allocatie nooit wordt vrijgegeven. De cyclus doorbreken met `Weak`, dat een niet-bezittende referentie vasthoudt, herstelt correct opruimen. **Wanneer verdient `Box` de voorkeur boven `Rc`?** Telkens als één eigenaar volstaat. `Box` heeft geen reference-counting-overhead en is daarmee de standaardkeuze voor heap-allocatie, recursieve types en trait-objecten. Grijp pas naar `Rc` wanneer er echt gedeeld eigenaarschap nodig is. ## Conclusie Rust smart pointers maken van ownership geen beperking maar een set samen te stellen bouwstenen. De keuze ertussen volgt direct uit de vorm van het probleem: - Grijp naar `Box` wanneer een waarde één heap-eigenaar nodig heeft, een recursief type een vaste grootte nodig heeft of een functie een trait-object teruggeeft. - Gebruik `Rc` voor meerdere eigenaren op één thread en schakel over naar `Arc` zodra eigenaarschap een threadgrens overschrijdt. - Voeg `RefCell` toe voor interior mutability in single-threaded code, en `Mutex` voor het concurrente equivalent, waarbij borrow- en lock-guards kortlevend blijven. - Combineer ze bewust: `Rc>` voor gedeelde muteerbare toestand op één thread, `Arc>` over threads heen. - Let op referentiecycli tussen getelde pointers en doorbreek ze met `Weak` om lekken te voorkomen. - Kies standaard het minst krachtige type en laat de compiler aangeven wanneer meer mogelijkheden nodig zijn. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/nl/blog/rust/rust-smart-pointers-box-rc-arc-refcell