Boxing

Lecture 5 min. ‱

Bonjour à toutes et à tous 😀

Si l’on se limitait aux rĂ©fĂ©rences, le langage Rust serait bien pauvre.

Heureusement, des mécanismes existent et enrichissent de maniÚres considérables les possibilités offertes.

Dans cet article, nous allons expliquer la maniÚre dont Rust à implémenté le mécanisme largement répandu de boxing.

Dans la section sur la heap nous avons dĂ©clarĂ© une String, nous avons dĂ©clarĂ© qu’une partie vivait dans une frame de la stack et les donnĂ©es dans la heap.

Mais nous n’avons pas trop Ă©tĂ© dans le dĂ©tail du fonctionnement, ni comment, nous nous pourrions mimer ce fonctionnement.

C’est ce que nous allons faire tout de suite en nous crĂ©ant des donnĂ©es qui au lieu de vivre dans la mĂ©moire stack vont ĂȘtre stockĂ©es dans la heap.

Déclarons une structure Person

struct Person {
    name: String,
    age: u8
}

Elle contient deux champs:

Déclarons une instance de Person et affectons-la à la variable p.

Nous nous retrouvons donc à avoir un espace mémoire dans la Stack qui est référencé par p.

Mais ce n’est pas tout, car p.name rĂ©fĂ©rence aussi sa slice qui vie dans la Heap. (ici initialisĂ© Ă  “toto”)

Nous possédons également p.age qui réside dans la Stack.

Nous désirons maintenant envoyer notre instance de Person dans la Heap.

Pour cela nous allons utiliser l’un des outils que la bibliothùque standard de Rust nous fourni.

Il s’agit des Box.

La syntaxe est simple.

Box::new(12);

Nous avons maintenant le nombre 12 qui est stocké dans la Heap et non dans la Stack.

Appliquons cela Ă  notre p.

Lq signature de Box::new est

fn new(x: T) -> Box<T>;

Ce qui signifie que new prend l’ownership de x, autrement dit ce qui est copiable est copiĂ© sinon on dĂ©place.

Person n’est pas Copy, on dĂ©place donc p dans Box::new.

Maintenant que p a quittĂ© main, il faut de la place pour l’accueillir quelque part, car dans le cas contraire, Ă  l’issue de l’exĂ©cution de Box::new, l’instance de Person sera dĂ©truite.

Pour cela, nous allons allouer suffisamment de place dans la Heap pour recevoir notre instance Person.

Puis nous allons déplacer le contenu référencé précédemment par p dans cette zone allouée dans la Heap.

Créer une référence pour ne pas perdre nos données dans la Heap.

Maintenant que Box::new s’est exĂ©cutĂ©e, il est temps de rĂ©cupĂ©rer ce qui a Ă©tĂ© produit dans une variable box.

On déplace alors la référence du contexte de Box::new vers celui de main.

Nous avons maintenant dans main, une variable box qui référence un objet dans la stack qui référence un objet dans la Heap.

La suite vous la connaissez, la frame de Box::new est détruite.

Maintenant, pourquoi s’ennuyer avec ce type Box<T> et pas juste faire &T mais vers la Heap ?

Et bien parce que la structure Box possÚde, outre sa faculté à allouer de la Heap, la capacité de se cloner.

Et c’est ce que nous allons voir tout de suite.

On appelle la méthode .clone car Box<T> implémente Clone.

Attention

À condition que T soit lui-mĂȘme Clone

Ce simple box.clone, dĂ©clenche toute une sĂ©rie d’évĂšnements.

Premiùrement, on borrow boxen &box que l’on copie ensuite dans Box::clone.

Puis l’on appelle la mĂ©thode T::Clone de ce que l’on box en copiant la rĂ©fĂ©rence qui est Ă  l’intĂ©rieur de la Box que l’on souhaite cloner.

Cela va avoir pour effet de rĂ©aliser l’allocation dans Heap de l’espace requis.

Puis l’on clone rĂ©ellement la structure et la String qui est associĂ©e.

On récupÚre une référence vers la zone mémoire allouée.

Que l’on vient stocker dans data.

On créé alors une nouvelle Box que l’on initialise avec une copie de la rĂ©fĂ©rence data et donc vers le “bon endroit” en Heap.

La méthode T::clone se termine, on nettoie la frame

On dĂ©place la nouvelle Box dans le contexte main et on l’associe Ă  la variable box_clone.

La méthode Box::clone se termine, on nettoie la frame

Nous nous retrouvons alors avec deux Box qui pointent vers deux structures indépendantes.

Et maintenant regardons ce qui se passe lors de la libération mémoire.

Disons que c’est box qui meurt en premier.

Le drop est déclenché et la mémoire Heap alloué est libérée.

Mais pas celle de box_clone qui est totalement indépendante.

Il faudra que drop se déclenche également dessus.

Finalement la méthode main se termine.

Et la frame est détruite avec toutes les références vers la Heap.

 

Attention

Comme vous avez pu l’observer, le clone d’une Box est loin d’ĂȘtre gratuit.

Il est Ă  utiliser comme tout clone si vous savez ce que vous clonez