Skip to content

Modul 11 — Smart Pointer & der Heap

Box, Rc, RefCell: Werte auf den Heap bringen, Besitz teilen, Mutation durch gemeinsame Handles — die Werkzeuge über dem Ownership-Modell.

Fortschritt0/4 Lektionen
41

Box: der Zeiger auf den Heap

Lektion 41 von 4

Bisher lebten deine Werte auf dem Stack — mit bekannter, fester Größe. Box verschiebt den Inhalt auf den Heap; auf dem Stack bleibt nur ein dünner Zeiger, der den Wert besitzt:

fn main() {
    let gross = Box::new([0u8; 4096]);

    println!("erstes Byte: {}", gross[0]);
    println!("Länge: {}", gross.len());
}

Dank Deref verhält sich der Box-Zeiger wie der Wert selbst: Index-Zugriff, Methoden, Dereferenzierung mit * — alles funktioniert direkt. Beim Drop wird der Heap-Speicher freigegeben. Ein Besitzer, eine Freigabe — dein Ownership-Modell, nur mit Umleitung über den Heap.

let data = [0u8; 4096];
data

4096 Bytes auf dem Stack — jeder Funktionsaufruf kopiert den Array.

Schritt 1 von 3

Zwei klassische Einsatzfälle:

  • Rekursive Typen — eine verkettete Liste enthält sich selbst; ohne Box kennt der Compiler die Größe nicht (E0072). Der Box-Zeiger hat feste Größe und bricht den Kreis. Die Übung baut genau das.
  • Einheitliche Fehler — ein Tool, das Datei- UND Parse-Fehler wirft:
use std::error::Error;

fn alter_von(zeile: &str) -> Result<u32, Box<dyn Error>> {
    let (_, wert) = zeile
        .split_once('=')
        .ok_or("Zeile ohne Gleichheitszeichen")?;
    Ok(wert.trim().parse::<u32>()?)
}

fn main() {
    println!("{:?}", alter_von("alter=30"));
}

Box<dyn Error> ist der pragmatische Fehlertyp für Programme: jede konkrete Fehlerart passt hinein, ? konvertiert automatisch.

Wann Box?

  • Rekursive Datentypen — der Größe-Kreisbruch
  • Große Werte, die du verschieben willst, ohne zu kopieren
  • Trait-Objekte — die Fehler-Box mit dyn Error versteckt die Größe hinter einem Zeiger

Übung: die rekursive Liste

🧩 Übung m11-l1-e1

🔮 Vorhersage: Was passiert beim Ausführen?

Editor wird geladen…
KI-Tutor (sokratisch — keine Komplettlösungen)

✅ Wichtige Erkenntnisse

0/3

Haken setzen, um deinen Lernfortschritt zu markieren:

42

Rc: Besitz teilen

Lektion 42 von 4

Box hat genau einen Besitzer. Manchmal brauchen denselben Wert aber mehrere: eine Konfiguration, die zwei Module lesen; ein Knoten, auf den mehrere Datenstrukturen zeigen. Rc (Reference Counted) erlaubt mehrere Besitzer — zur Laufzeit gezählt:

use std::rc::Rc;

fn main() {
    let konfig = Rc::new(vec![10, 20, 30]);

    let kopie_a = Rc::clone(&konfig);
    let kopie_b = Rc::clone(&konfig);

    println!("a-Summe: {}", kopie_a.iter().sum::<u32>());
    println!("Besitzer: {}", Rc::strong_count(&konfig));
}

Rc::clone kopiert NICHTS — es erhöht nur den Zähler. Alle drei Bindungen zeigen auf denselben Heap-Wert; fällt der letzte Besitzer weg, wird er freigegeben. strong_count sagt dir, wie viele es gerade sind.

Der Preis: Rc-Inhalte sind nur lesbar. Mit mehreren Besitzern könnte eine Änderung über einen Zeiger invalidieren, was ein anderer gerade liest — genau das verbietet Rusts Aliasing-Regel. Für Mutation braucht es den nächsten Baustein.

Und Rc bleibt zuhause: sein Zähler ist nicht atomar, also ist Rc ausdrücklich nicht thread-safe. Für Threads gibt es Arc — dasselbe Muster mit atomarem Zähler (Modul 12).

Smart-Pointer-WerkstattBereit
Editor wird geladen…

Übung: geteilter Besitz

🧩 Übung m11-l2-e1

🔮 Vorhersage: Was passiert beim Ausführen?

Editor wird geladen…
KI-Tutor (sokratisch — keine Komplettlösungen)

✅ Wichtige Erkenntnisse

0/3

Haken setzen, um deinen Lernfortschritt zu markieren:

43

RefCell: Mutation zur Laufzeit

Lektion 43 von 4

Die Borrow-Regeln gelten zur Compile-Zeit — meistens gut, manchmal zu streng: Ein Logger wird von vielen Stellen geteilt und darf trotzdem wachsen. RefCell verlagert die Prüfung in die Laufzeit:

use std::cell::RefCell;

fn main() {
    let log = RefCell::new(Vec::new());

    log.borrow_mut().push(String::from("start"));

    {
        let lesend = log.borrow();
        println!("Einträge: {}", lesend.len());
    }

    log.borrow_mut().push(String::from("ende"));
    println!("{:?}", log.borrow());
}

borrow() leiht lesend (beliebig oft), borrow_mut() exklusiv. Die Regel bleibt dieselbe — Shared XOR Exclusive — nur dass RefCell sie zählt: ein Konflikt paniziert sofort, mit präziser Meldung. Der innere Block gibt den lesenden Borrow zurück, bevor borrow_mut() kommt.

Die Kombo aus beiden Welten ist der Klassiker: Rc + RefCell — Rc teilt den Besitz, RefCell erlaubt die Änderung durch den gemeinsamen Handle. Geteilter, veränderlicher Zustand ohne unsafe.

Runtime-Borrows im Griff

  • borrow() = lesender Zähler hoch; borrow_mut() = exklusiv, paniziert bei Konflikt
  • try_borrow_mut() liefert Result statt Panic — für abfangbare Konflikte
  • Rc + RefCell = geteilter, veränderlicher Zustand (single-threaded)

Übung: der Runtime-Borrow

🧩 Übung m11-l3-e1

🔮 Vorhersage: Was passiert beim Ausführen?

Editor wird geladen…
KI-Tutor (sokratisch — keine Komplettlösungen)

✅ Wichtige Erkenntnisse

0/3

Haken setzen, um deinen Lernfortschritt zu markieren:

44

Mini-Projekt: der geteilte Tracker

Lektion 44 von 4

Das Szenario vorweg — dann baust du die Lösung:

Praxis-Szenario: Die Ausgabenliste, die jeder sehen darf

Dein Team bucht Ausgaben (Server, Domain, Kaffee) in einer geteilten Liste. Bisher: drei Kollegen, drei eigene Kopien der Liste, dreimal wöchentlich manuell zusammenführen — und dreimal pro Monat falsche Summen. Die Anforderung: EINE Liste im Speicher, auf die mehrere Stellen schreiben und lesen, ohne dass sich jemand Kopien zieht oder die Summe aus dem Takt kommt.

🧩 Übung m11-l4-e1

🔮 Vorhersage: Was passiert beim Ausführen?

Editor wird geladen…
KI-Tutor (sokratisch — keine Komplettlösungen)

Was du in Modul 11 geschafft hast

  • Box: Heap mit einem Besitzer — inklusive Rekursions-Ausweg und dyn Error
  • Rc: geteilter Besitz per Zähler — read-only, billig zu klonen
  • RefCell: Borrow-Regeln zur Laufzeit; Rc + RefCell = geteilter veränderlicher Zustand
  • Ein Tracker mit EINER Quelle der Wahrheit

✅ Wichtige Erkenntnisse

0/3

Haken setzen, um deinen Lernfortschritt zu markieren:

Modul-Checkpoint

Checkpoint: Modul 11

Bestehensgrenze: 80 %. Der Versuch wird bewertet und zählt für das Modul-Gate.

This site uses essential cookies for Stripe payments. No tracking cookies.