ProgrammationDéveloppeur C++ Middle

Expliquez les différences entre un pointeur classique et un pointeur intelligent (par exemple, std::unique_ptr) en C++. Pourquoi les pointeurs intelligents rendent-ils les programmes plus fiables ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question :

Les pointeurs classiques (bruts) sont le mécanisme traditionnel en C++ pour travailler avec la mémoire dynamique. C'est un mécanisme abstrait universel, mais, malheureusement, très sujet à des erreurs : fuites de mémoire, suppressions doubles, erreurs de pointeurs pendants. C'est pourquoi, avec C++11, la bibliothèque standard inclut des pointeurs intelligents - des classes шаблонные (std::unique_ptr, std::shared_ptr, std::weak_ptr), qui gèrent automatiquement la durée de vie de l'objet.

Problème :

Lors de l'utilisation de pointeurs classiques, la responsabilité de l'allocation et de la libération de la mémoire incombe au programmateur. Des erreurs dans la libération de la mémoire entraînent des fuites (memory leaks), des corruptions de données, des plantages de programmes. Des cas particulièrement complexes surviennent lors du traitement d'exceptions ou lors du passage de pointeurs à d'autres fonctions.

Solution :

Les pointeurs intelligents encapsulent la mémoire allouée et la libèrent automatiquement lorsqu'il n'y a plus de propriétaires. Ils implémentent RAII. std::unique_ptr assure une possession exclusive, std::shared_ptr - partagée, std::weak_ptr - non contrôlante (pour éviter les "cycles de référence").

Exemple de code :

#include <memory> void foo() { std::unique_ptr<int> p = std::make_unique<int>(5); // la mémoire sera libérée même en cas d'exception // ... }

Caractéristiques clés :

  • Les pointeurs intelligents libèrent automatiquement les ressources à la destruction
  • std::unique_ptr interdit la copie, seule la sémantique du déplacement (move) est autorisée
  • std::shared_ptr implémente le "compte de références"

Questions pièges.

Peut-on utiliser std::unique_ptr pour un tableau créé avec new[] ?

Non, pour les tableaux, utilisez std::unique_ptr<T[]> : ainsi, delete[] sera appelé au lieu de delete.

std::unique_ptr<int[]> arr(new int[10]);

Les pointeurs intelligents standard peuvent-ils prévenir toutes les fuites de mémoire possibles ?

Non. Par exemple, des références cycliques entre std::shared_ptr entraîneront des fuites. Pour briser ces cycles, on utilise std::weak_ptr.

Les pointeurs intelligents peuvent-ils "supprimer" le même objet deux fois ?

Non, à condition de ne pas violer la logique de propriété (ne pas utiliser de pointeurs bruts !). Si vous copiez manuellement un pointeur brut, la destruction peut se produire deux fois.

Erreurs typiques et anti-patterns

  • Copier std::unique_ptr - entraînera une erreur de compilation
  • Utiliser simultanément un pointeur intelligent et un pointeur brut sur le même objet
  • Ne pas utiliser std::weak_ptr pour résoudre des dépendances cycliques

Exemple de la vie réelle

Cas négatif

Des pointeurs bruts sont utilisés, la mémoire est libérée manuellement, en cas d'exception, la mémoire n'est pas libérée.

Avantages :

  • Compréhensible dans des tâches simples

Inconvénients :

  • Fuites de mémoire régulières
  • Suppression potentielle double
  • Difficulté à maintenir le code

Cas positif

Utilisation de std::unique_ptr et std::make_unique pour créer des objets et les passer à des fonctions.

Avantages :

  • Pratiquement impossible d'avoir des fuites de mémoire
  • Interface RAII, possession et passage d'objets simples

Inconvénients :

  • Nécessite une compréhension de la sémantique des déplacements et du fonctionnement de la bibliothèque standard