Dans le langage Rust, la gestion de la mémoire a traditionnellement été considérée comme l'un des problèmes les plus complexes de la programmation basse niveau. Avant l'apparition de Rust, de nombreux langages exigeaient une gestion manuelle de la mémoire (comme C/C++), ce qui entraînait des fuites et des corruptions de données. Rust a abordé la question différemment — des collections comme Vec<T> utilisent une stratégie de gestion de la mémoire automatique et sécurisée, contrôlant le moment de l'allocation, du redimensionnement et de la libération de mémoire grâce à un système de possession et de prêts.
Le problème résidait dans le fait que la plupart des langages soit abstraient trop les détails de l'allocateur (GC), soit rendent le programmeur responsable de tout (malloc/free). Dans le cas des tableaux dynamiques, il est crucial de surveiller les fuites et les dépassements de tableau, ainsi que de ne pas violer la possession.
La solution en Rust — l'automatisation par le biais d'abstractions sûres. Vec<T> alloue de la mémoire sur le tas, augmente dynamiquement sa taille (généralement avec une croissance exponentielle), et libère tout lorsque l'on sort de la portée (RAII).
Exemple de code :
fn main() { let mut v: Vec<i32> = Vec::new(); v.push(1); v.push(2); v.push(3); // L'ajout entraîne une augmentation de la taille et une réallocation de mémoire println!("Vector: {:?}", v); // À la sortie du main, la mémoire est libérée automatiquement }
Caractéristiques clés :
Vec<T> alloue de la mémoire à l'avance et la réalloue si nécessaireQuelle est la complexité d'augmentation d'un tableau lors de l'ajout d'éléments à Vec ?
En général, la complexité de push est amortie O(1), cependant, lorsque le tableau déborde, une nouvelle zone de mémoire est allouée (environ le double de la taille), et tous les éléments sont copiés. Ce moment est la seule exception où l'opération devient O(n).
Que se passe-t-il lorsque l'on essaie d'accéder à un élément hors de portée via v[index] ?
L'utilisation de crochets entraîne une panique lors du dépassement de limite. Il faut utiliser la méthode .get(), qui renvoie Option et permet de gérer l'erreur de manière sécurisée.
let element = v.get(10); // None, si l'index n'existe pas
Peut-on utiliser une référence à un élément de Vec après un éventuel agrandissement (resize) du vecteur ?
Non, après un changement de taille du vecteur (par exemple, via push lors d'un débordement), toute la mémoire peut être déplacée, et les anciennes références deviennent invalides — une erreur de compilation se produit (ou un comportement indéfini dans un bloc unsafe, si vous les utilisez manuellement).
Un développeur implémente un cache de messages basé sur Vec<T> et expose des références à des éléments. Après une nouvelle insertion, il y a une réallocation de la mémoire, et toutes les références existantes deviennent "pendantes". Et l'application plante.
Avantages :
Inconvénients :
On utilise soit une identification interne des éléments (indices/clés + vérification de validité), soit on ne renvoie que des copies/valeurs immuables, il n'est pas permis de conserver des références de longue durée sur les éléments de Vec.
Avantages :
Inconvénients :