Blog Alphorm Logo de blog informatique spécialisé en technologie et solutions IT
  • Développement
  • 3D et Animation
  • Cybersécurité
  • Infrastructure
  • Virtualisation
  • Réseaux
  • Bureautique
  • BDD
En cours de lecture : Utilisation efficace de weak_ptr en C++
Agrandisseur de policeAa
Blog AlphormBlog Alphorm
  • Développement
  • 3D et Animation
  • Cybersécurité
  • Infrastructure
  • Virtualisation
  • Réseaux
  • Bureautique
  • BDD
Search
  • Développement
  • 3D et Animation
  • Cybersécurité
  • Infrastructure
  • Virtualisation
  • Réseaux
  • Bureautique
  • BDD
Suivez-nous
© Alphorm 2024 - Tous droits réservés
Développement

Utilisation efficace de weak_ptr en C++

L'Équipe Alphorm Par L'Équipe Alphorm 15 janvier 2025
Partager
Partager

Les références circulaires en C++ peuvent causer des fuites de mémoire.

Ces cycles empêchent la libération automatique des ressources, entraînant une consommation excessive de mémoire.

L’utilisation de weak_ptr casse ces cycles, permettant une gestion efficace de la mémoire dans vos projets C++.

Table de matière
Introduction au weak_ptr en C++Comprendre les pointeurs intelligents weak_ptrSyntaxe et utilisation du weak_ptr C++Conclusion sur les références circulairesFAQConclusion

Formation Initiation Programmation C++ : Les fondamentaux

Maîtrisez le C++ en créant un jeu console et boostez vos compétences

Découvrir cette formation

Introduction au weak_ptr en C++

La bibliothèque standard C++ propose des smart pointers comme shared_ptr, unique_ptr et weak_ptr. Ce e-book se concentre sur le weak_ptr, un outil souvent mal compris mais extrêmement utile dans les bons contextes. À travers ce chapitre, nous explorerons en profondeur son fonctionnement, sa syntaxe, ses cas d’usage et son rôle dans les projets modernes.

Comprendre les pointeurs intelligents weak_ptr

Un weak_ptr est un pointeur non-intrusif. Contrairement à shared_ptr, il n’incrémente pas le compteur de références de la ressource. Il permet de résoudre des problèmes spécifiques comme les références circulaires .

Exemple de Référence Circulaire

Supposons deux objets A et B, chacun contenant un shared_ptr vers l’autre. Cela crée un cycle, empêchant la libération automatique des ressources.

				
					
 class A;
class B;
struct A {
std::shared_ptr<B> b_ptr;
};
struct B {
std::shared_ptr<A> a_ptr;
};

				
			

Problème des Cycles de Référence :

Si a_ptr dans B était un shared_ptr, alors :

  • A maintiendrait B en vie avec son b_ptr.
  • B maintiendrait A en vie avec son a_ptr.
Erreur Courante : Lorsque deux objets utilisent des shared_ptr pour se référencer mutuellement, la mémoire n’est jamais libérée.

Solution avec weak_ptr :

  • L’utilisation de weak_ptr pour a_ptr dans B casse le cycle.
  • weak_ptr n’augmente pas le compteur de références, permettant ainsi la libération des objets quand plus aucun autre shared_ptr ne les référence.

Avec un weak_ptr, ce problème est éliminé, car il n’affecte pas le compteur de références.

				
					
 struct A {
std::shared_ptr<B> b_ptr;
};
struct B {
std::weak_ptr<A> a_ptr;
};

				
			

Rôle et Utilité

Rôle
Description
Exemple
Résolution de cycles de références
Évite les cycles entre objets en utilisant weak_ptr pour observer sans maintenir en vie.
Relation parent-enfant dans un arbre : parent avec shared_ptr, enfant avec weak_ptr vers le parent.
Observation sans influence sur la durée de vie
Permet d’observer une ressource sans affecter sa durée de vie, évitant les rétentions inutiles.
Gestionnaire d’événements : weak_ptr pour observer un objet sans empêcher sa destruction.
Cache ou surveillance d’objets
Stocke une référence faible à une ressource dans un cache, la recrée si elle n’est plus disponible.
Cache d’objets :weak_ptrpour vérifier la disponibilité d’une ressource avant de la recréer.

Syntaxe et utilisation du weak_ptr C++

Création et Initialisation

La création et l’utilisation d’un weak_ptr en C++ reposent sur une étape clé : l’ initialisation à partir d’un shared_ptr existant . Cette étape est cruciale car un weak_ptr ne peut pas être directement associé à une ressource brute, comme un pointeur classique ou une valeur

Exemple du code :

				
					
 #include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> sp = std::make_shared<int>(42);  // Création d’un shared_ptr
std::weak_ptr<int> wp = sp;                          // Création d’un weak_ptr depuis le shared_ptr
std::cout << "Valeur de sp : " << *sp << '\n';
return 0;
}

				
			
Astuce Pratique : Toujours initialiser un weak_ptr avec un shared_ptr existant pour garantir sa validité.

Exemple d’exécution :

Exemple C++ avec weak_ptr et shared_ptr

Utilisation de lock()

La méthode lock() permet d’obtenir un shared_ptr temporaire si la ressource est encore disponible. Sinon, elle retourne un pointeur nul.

Erreur Courante :
Déréférencer un weak_ptr directement sans utiliser lock(), ce qui entraîne des erreurs de compilation.
Ne pas vérifier si lock() retourne un pointeur valide avant de l’utiliser.

Exemple du code :

				
					
 #include <iostream>
#include <memory> // Pour std::shared_ptr et std::weak_ptr
int main() {
std::weak_ptr<int> wp; // Déclaration d'un weak_ptr
{
// Création d'un shared_ptr dans un bloc limité
auto sp = std::make_shared<int>(42);
wp = sp; // Initialisation du weak_ptr à partir du shared_ptr
std::cout << "Dans le bloc : \n";
std::cout << "Valeur de la ressource : " << *sp << '\n';
std::cout << "use_count : " << sp.use_count() << '\n';
} // Le shared_ptr est détruit ici, et la ressource est libérée.
// Verrouillage du weak_ptr pour vérifier si la ressource est encore disponible
if (auto locked_sp = wp.lock()) {
std::cout << "Ressource disponible : " << *locked_sp << '\n';
} else {
std::cout << "La ressource a été libérée.\n";
}
return 0;
}

				
			

Explications

  • Bloc de portée :Le shared_ptr est créé à l’intérieur d’un bloc { … }. Une fois le bloc terminé, le shared_ptr est détruit, ce qui entraîne la libération de la ressource qu’il gère.
  • weak_ptr :Le weak_ptr (wp) observe la ressource sans prolonger sa durée de vie.
  • lock() :Cette méthode est utilisée pour obtenir un shared_ptr temporaire si la ressource est toujours valide. Si elle est déjà libérée, lock() retourne un pointeur nul.

Exemple d’exécution :

Exemple de code C++ utilisant weak_ptr

Cela montre que le weak_ptr permet d’observer une ressource sans empêcher sa libération.

Observer sans Verrouillage

Un weak_ptr permet d’observer une ressource sans prolonger sa durée de vie. Cela est essentiel dans des systèmes où la libération rapide des ressources est cruciale.

Exemple du code :

				
					
 #include <iostream>
#include <memory>
int main() {
std::weak_ptr<int> observer;
{
auto sp = std::make_shared<int>(100); // Création d'une ressource gérée par shared_ptr
observer = sp; // Le weak_ptr observe la ressource
std::cout << "Dans le bloc : Valeur = " << *sp << '\n';
} // La ressource est libérée ici
if (auto sp = observer.lock()) {
std::cout << "Ressource toujours disponible : " << *sp << '\n';
} else {
std::cout << "La ressource a été libérée.\n";
}
return 0;
}

				
			

Explications du Code :

  • Le weak_ptr observe toujours la ressource.
  • Lorsque la ressource est libérée (en sortant du bloc), le weak_ptr ne prolonge pas sa durée de vie.

Exemple d’exécution :

Code C++ démontrant weak_ptr dans Visual Studio

Cache avec weak_ptr

Ce code montre comment utiliser un weak_ptr dans un système de cache pour maintenir des références légères à des ressources, sans les garder inutilement en mémoire. Cela permet de libérer des ressources lorsqu’elles ne sont plus activement utilisées, tout en les recréant automatiquement si nécessaire.

Exemple du code :

				
					
 #include <iostream>
#include <memory>
#include <unordered_map>
#include <string>
class Resource {
public:
Resource(const std::string& name) : name(name) {
std::cout << "Ressource " << name << " créée.\n";
}
~Resource() {
std::cout << "Ressource " << name << " détruite.\n";
}
void use() const {
std::cout << "Utilisation de la ressource " << name << ".\n";
}
private:
std::string name;
};
class Cache {
public:
std::shared_ptr<Resource> getResource(const std::string& key) {
if (auto res = cache[key].lock()) { // Ressource encore disponible
std::cout << "Ressource " << key << " récupérée du cache.\n";
return res;
} else { // Ressource non disponible, création d'une nouvelle
auto newRes = std::make_shared<Resource>(key);
cache[key] = newRes;
return newRes;
}
}
private:
std::unordered_map<std::string, std::weak_ptr<Resource>> cache; // Cache avec weak_ptr
};
int main() {
Cache cache;
{
auto res1 = cache.getResource("res1");
res1->use();
} // res1 sort du scope et peut être détruit
std::cout << "Après suppression de res1.\n";
cache.getResource("res1")->use(); // Nouvelle instance de res1 créée si nécessaire
return 0;
}

				
			
Astuce Pratique : Vérifiez toujours la validité d’une ressource dans le cache avec lock(). Si elle est invalide, recréez-la :

Explications du Code :

Classe Resource :

  • Représente une ressource coûteuse ou unique.
  • Imprime un message lorsqu’elle est créée ou détruite pour illustrer le cycle de vie de l’objet.
  • Dispose d’une méthode use pour simuler une opération sur la ressource.

Classe Cache :

  • Utilise un conteneur std ::unordered_map pour stocker des références faibles (weak_ptr) à des ressources identifiées par des clés (std::string).
  • Méthode principale :getResource :
  • Vérifie si une ressource est encore disponible via lock().
  • Si la ressource est valide, elle est récupérée depuis le cache.
  • Si elle n’est plus disponible, une nouvelle instance est créée et ajoutée au cache.

Fonction principale main :

  • Montre comment une ressource peut être récupérée, utilisée, libérée, puis recréée automatiquement si nécessaire.

Exemple d’exécution :

Console Visual Studio montrant l'utilisation d'un weak_ptr

Cas d’Utilisation et Bonnes Pratiques

Imaginez une structure hiérarchique où chaque nœud pointe vers son parent et ses enfants. En utilisant un weak_ptr pour pointer vers le parent, vous évitez les cycles de références.

				
					
 #include <iostream>
#include <memory>
#include <vector>
struct Node {
std::weak_ptr<Node> parent;
std::vector<std::shared_ptr<Node>> children;
int value;
Node(int val) : value(val) {}
};
int main() {
auto root = std::make_shared<Node>(1);
auto child1 = std::make_shared<Node>(2), child2 = std::make_shared<Node>(3);
root->children = {child1, child2};
child1->parent = root; child2->parent = root;
std::cout << "Racine : " << root->value << '\n';
for (const auto& child : root->children)
std::cout << " Enfant : " << child->value
<< " (Parent : " << child->parent.lock()->value << ")\n";
return 0;
}

				
			

Exemple d’exécution :

Code C++ avec weak_ptr et console

Conclusion sur les références circulaires

Le weak_ptr est un outil puissant pour observer des ressources sans influencer leur durée de vie. Bien qu’il ne soit pas aussi connu que ses cousins shared_ptr et unique_ptr, son rôle est essentiel dans des scénarios spécifiques, comme la gestion des références circulaires ou la création de systèmes légers d’observation.

En combinant théorie, exemples pratiques et explications détaillées, ce guide vous donne une compréhension complète du weak_ptr. Il vous permettra d’écrire un code plus sûr et plus efficace.

Formez-vous gratuitement avec Alphorm !

Maîtrisez les compétences clés en IT grâce à nos formations gratuites et accélérez votre carrière dès aujourd'hui.

Démarrer gratuitement
illustration processus de paiement en ligne avec étapes claires et convivialité

FAQ

Qu'est-ce qu'un weak_ptr en C++ ?
Un weak_ptr en C++ est un pointeur non-intrusif qui permet d’observer une ressource sans affecter son compteur de références. Contrairement à shared_ptr, il ne prolonge pas la durée de vie de l’objet. Cela est particulièrement utile pour éviter les références circulaires, où deux objets se pointent mutuellement, empêchant ainsi la libération de la mémoire. En utilisant weak_ptr, on peut casser ces cycles et s’assurer que la mémoire est libérée correctement quand les ressources ne sont plus nécessaires.
Comment weak_ptr résout-il le problème des références circulaires ?
Le weak_ptr résout le problème des références circulaires en ne participant pas au comptage de références de l’objet qu’il observe. Dans une situation où deux objets se référencent mutuellement via shared_ptr, l’utilisation de weak_ptr pour l’un des pointeurs casse le cycle. Cela permet aux objets d’être correctement détruits lorsque plus aucun shared_ptr ne les référence, libérant ainsi la mémoire utilisée par les objets.
Comment initialiser un weak_ptr en C++ ?
Pour initialiser un weak_ptr en C++, il est nécessaire de le faire à partir d’un shared_ptr existant. On ne peut pas associer directement un weak_ptr à une ressource brute. Par exemple, si vous avez un shared_ptr ‘sp’, vous pouvez créer un weak_ptr ‘wp’ comme suit : ‘std::weak_ptr wp = sp;’. Cette initialisation garantit que le weak_ptr observe la même ressource que le shared_ptr sans la prolonger.
Quelle est l'importance de la méthode lock() avec weak_ptr ?
La méthode lock() est essentielle pour travailler avec weak_ptr car elle permet de convertir temporairement un weak_ptr en shared_ptr, si la ressource est encore disponible. Si la ressource a été libérée, lock() retourne un pointeur nul. Cela évite les erreurs de segmentation en essayant de déréférencer un weak_ptr directement. En utilisant lock(), vous pouvez vérifier la validité de la ressource avant de l’utiliser.
Comment utiliser weak_ptr dans un système de cache ?
Dans un système de cache, un weak_ptr est utilisé pour maintenir une référence faible à une ressource. Cela permet de libérer la ressource lorsque plus aucun shared_ptr ne la référence, mais aussi de la recréer si elle est de nouveau nécessaire. Ainsi, un weak_ptr dans un cache n’empêche pas la libération de la mémoire, tout en permettant la récupération de la ressource si elle est toujours valide, optimisant ainsi l’utilisation des ressources.

Conclusion

En maîtrisant l’utilisation de weak_ptr, vous pouvez créer des applications C++ plus efficaces et gérer la mémoire de manière plus précise. Quels autres scénarios pourriez-vous optimiser en utilisant weak_ptr ?

ÉTIQUETÉ : Langage C++
Facebook
Twitter
LinkedIn
Email
WhatsApp
Par L'Équipe Alphorm
Démocratiser la Connaissance Informatique pour Tous !
Suivre :
L'Équipe Alphorm, c'est la démocratisation de la connaissance informatique. Passionnés et dévoués, nous sommes là pour vous guider vers le succès en rendant la technologie accessible à tous. Rejoignez notre aventure d'apprentissage et de partage. Avec nous, le savoir IT devient une ressource inspirante et ouverte à tous dans un monde numérique en constante évolution.

Derniers Articles

  • Techniques pour gérer les fichiers texte en C#
  • Créer et lire un fichier CSV avec C#
  • JSON : Comprendre et Utiliser Efficacement
  • Créer une Base SQLite dans C#
  • Lecture des données SQLite simplifiée
Laisser un commentaire Laisser un commentaire

Laisser un commentaire Annuler la réponse

Vous devez vous connecter pour publier un commentaire.

Blog Alphorm
  • Développement
  • 3D et Animation
  • Cybersécurité
  • Infrastructure
  • Virtualisation
  • Réseaux
  • Bureautique
  • BDD
En cours de lecture : Utilisation efficace de weak_ptr en C++

© Alphorm - Tous droits réservés