Passer au contenu principal
eLearner.app
Module 6 · Leçon 2 sur 212/14 dans le cours~15 min
Leçons du module (2/2)

Smart Pointers: Box et Rc

Un smart pointer (pointeur intelligent) est une structure de données qui se comporte comme un pointeur, mais possède des métadonnées et des fonctionnalités supplémentaires (comme le comptage des références ou la gestion automatique de la mémoire).

En Rust, les références ordinaires (comme &) ne font qu'emprunter des données. Les smart pointers, quant à eux, possèdent souvent les données vers lesquelles ils pointent. Des exemples courants incluent String et Vec<T>, mais la bibliothèque standard en fournit d'autres plus spécialisés.


Box<T> pour allouer dans le Tas (Heap)

Le smart pointer le plus simple est Box<T>, qui stocke les données dans le tas plutôt que sur la pile. Sur la pile ne reste que le pointeur vers la donnée allouée dans le tas.

Il est principalement utilisé dans les cas suivants :

  1. Lorsque vous avez un type dont la taille ne peut pas être connue au moment de la compilation (comme un type récursif), et que vous souhaitez utiliser une valeur de ce type dans un contexte qui nécessite une taille exacte.
  2. Lorsque vous souhaitez transférer de grandes quantités de données sans les copier.

Exemple de base :

Code
fn main() {
    let b = Box::new(5); // alloca il valore 5 nello heap
    println!("b = {}", *b); // de-referenzia con * per leggere il valore
}

Types Récursifs et Cons List

Un type récursif est un type qui peut contenir une valeur de lui-même en son sein. Rust doit connaître la taille exacte d'un type au moment de la compilation. Comme la profondeur d'un type récursif pourrait être infinie, le compilateur génère une erreur à moins d'utiliser un Box (qui a une taille fixe, puisqu'il s'agit d'un pointeur) :

Code
enum List {
    Cons(i32, Box<List>),
    Nil,
}

Rc<T> : Comptage des Références (Reference Counting)

Il existe des cas où une seule valeur peut avoir plusieurs propriétaires. Le smart pointer Rc<T> (Reference Counted) suit le nombre de références à une valeur pour déterminer si celle-ci est toujours utilisée. Si le décompte tombe à zéro, la ressource est libérée en toute sécurité.

[!NOTE] Rc<T> est utilisable exclusivement dans des scénarios mono-thread. Pour des scénarios multi-thread (concurrents), il faut utiliser Arc<T> (Atomic Reference Counted).

Code
use std::rc::Rc;

fn main() {
    let a = Rc::new(5);
    let b = Rc::clone(&a); // incrementa il contatore a 2
    println!("Riferimenti: {}", Rc::strong_count(&a));
}

À toi de jouer

Exercice 1 : Allouer avec Box

Exercice#rust.m6.l2.e1
Tentatives : 0Chargement…

Allouez une valeur entière égale à 42 dans le tas à l'aide de Box::new et assignez-la à une variable nommée val. Ensuite, affichez à l'écran la valeur stockée dans le Box en la déréférençant explicitement avec l'opérateur *.

Chargement de l'éditeur…
Afficher l'indice

Utilisez `let val = Box::new(42);` pour stocker la valeur dans le tas et déréférencez-la avec `*val` à l'intérieur de `println!`.

Solution disponible après 3 tentatives

Exercice 2 : Structure de données récursive (Cons List)

Exercice#rust.m6.l2.e2
Tentatives : 0Chargement…

Définissez un enum récursif nommé List contenant deux variantes : Cons qui renferme un tuple (i32, Box<List>), et Nil qui représente la fin de la liste. Dans le main, instanciez une liste chaînée contenant l'élément 1 suivi de Nil.

Chargement de l'éditeur…
Afficher l'indice

L'enum se déclare ainsi `enum List { Cons(i32, Box<List>), Nil }`. Instanciez la liste avec `List::Cons(1, Box::new(List::Nil))`.

Solution disponible après 3 tentatives

Exercice 3 : Partager la propriété avec Rc

Exercice#rust.m6.l2.e3
Tentatives : 0Chargement…

Utilisez std::rc::Rc pour créer un entier partagé contenant la valeur 100 au sein d'une variable a. Clonez la référence dans une variable b en utilisant Rc::clone. Enfin, affichez à l'écran le compteur de références actives à l'aide de la fonction Rc::strong_count.

Chargement de l'éditeur…
Afficher l'indice

Créez la valeur avec `Rc::new(100)`. Clonez avec `Rc::clone(&a)`et affichez le nombre de propriétaires avec`Rc::strong_count(&a)`.

Solution disponible après 3 tentatives