J'ai lu quelque part que, lors de l'utilisation de C ++, il est recommandé de ne pas utiliser de pointeur. Pourquoi les pointeurs sont-ils une si mauvaise idée lorsque vous utilisez C ++? Pour les programmeurs C habitués à utiliser des pointeurs, quelle est la meilleure alternative et approche en C ++?
45
NetConnection
instances qui se déconnectent du serveur ( stackoverflow.com/questions/14780456/… ), ainsi qu'un problème lié à la présence de plusieurs objets dans un programme qu'il refusera spécifiquement de collecter. ...GCRoots are never garbage collected.
et le paragraphe commençant parThe MMgc is considered a conservative collector for mark/sweep.
). Techniquement, il s'agit d'un problème dans Adobe Virtual Machine 2, pas AS3, mais lorsque vous rencontrez des problèmes de ce type dans les langages de niveau supérieur, dans lesquels la récupération de place est essentiellement intégrée, vous n'avez souvent aucun moyen véritable de déboguer dans le langage. ces questions complètement hors du programme. ...Réponses:
Je pense qu'ils signifient que vous devriez utiliser des pointeurs intelligents au lieu des pointeurs normaux.
En C ++, l'accent est mis sur la récupération de place et la prévention des fuites de mémoire (pour n'en nommer que deux). Les pointeurs sont une partie fondamentale du langage, il est donc pratiquement impossible de les utiliser, sauf dans les programmes les plus divers.
la source
Étant donné que c'est moi qui ai publié la polémique «N'utilisez pas d'indices fictifs», j'estime que je devrais faire un commentaire ici.
Tout d'abord, en tant que polémique, cela représente évidemment un point de vue extrême. Il existe certainement des utilisations légitimes des pointeurs (bruts). Mais moi (et de nombreux programmeurs professionnels C ++), maintenons que ces cas sont extrêmement rares. Mais ce que nous voulons vraiment dire est le suivant:
Première:
Ici, «propre mémoire» signifie essentiellement que
delete
ce pointeur est appelé à un moment donné (mais que c'est plus général que cela). Cette déclaration peut être considérée comme absolue. La seule exception concerne l’implémentation de votre propre pointeur intelligent (ou d’une autre stratégie de gestion de la mémoire). Et même là, vous devriez normalement toujours utiliser un pointeur intelligent à bas niveau.La raison en est assez simple: les pointeurs bruts qui possèdent leur propre mémoire introduisent une source d'erreur. Et ces erreurs sont prolifiques dans les logiciels existants: fuites de mémoire et double suppression - l'une des conséquences directes de la propriété de ressources peu claire (mais allant dans le sens opposé).
Ce problème peut être entièrement éliminé, pratiquement sans frais, en utilisant simplement des pointeurs intelligents au lieu de pointeurs bruts (attention: cela exige toujours de réfléchir, bien sûr; des pointeurs partagés peuvent conduire à des cycles et donc à des fuites de mémoire, mais cela est facile. évitable).
Seconde:
Contrairement à d'autres langages, C ++ supporte très bien la sémantique des valeurs et n'a tout simplement pas besoin de l'indirection des pointeurs. Cela n’a pas été immédiatement réalisé - historiquement, le C ++ a été inventé pour faciliter l’orientation facile des objets en C et s’appuie fortement sur la construction de graphes d’objets reliés entre eux par des pointeurs. Mais dans le C ++ moderne, ce paradigme est rarement le meilleur choix et les idiomes modernes du C ++ n’ont souvent pas besoin de pointeur . Ils opèrent sur des valeurs plutôt que des pointeurs.
Malheureusement, ce message n’a toujours pas été compris dans la plupart des utilisateurs C ++. En conséquence, la plupart du code C ++ écrit est toujours jonché de pointeurs superflus qui le rendent complexe, lent et défectueux / non fiable.
Pour ceux qui connaissent le C ++ moderne, il est clair que vous avez très rarement besoin de pointeurs (intelligents ou bruts; sauf lorsque vous les utilisez comme itérateurs). Le code résultant est plus court, moins complexe, plus lisible, souvent plus efficace et plus fiable.
la source
std::unique_ptr
. Aussi pourquoi pasptr_vec
? Mais généralement, un vecteur de valeur avec sera toujours échanger plus rapidement (surtout avec la sémantique de déplacement).boost::variant
avecrecursive_wrapper
est probablement ma solution préférée pour représenter un DAG.Tout simplement parce que vous avez à votre disposition des abstractions qui cachent les aspects les plus instinctifs de l’utilisation de pointeurs, tels que l’accès à la mémoire brute et le nettoyage après vos allocations. Avec les pointeurs intelligents, les classes de conteneur et les modèles de conception tels que RAII, la nécessité d'utiliser des pointeurs bruts est réduite. Cela dit, comme pour toute abstraction, vous devez comprendre comment ils fonctionnent avant de les dépasser.
la source
Relativement simplement, la mentalité C est "Vous avez un problème? Utilisez un pointeur". Vous pouvez le voir dans les chaînes de caractères C, les pointeurs de fonction, les pointeurs en tant qu'itérateurs, le pointeur à l'autre, le pointeur vide, même dans les débuts de C ++ avec des pointeurs membres.
Mais en C ++, vous pouvez utiliser des valeurs pour plusieurs ou toutes ces tâches. Besoin d'une abstraction de fonction?
std::function
. C'est une valeur qui est une fonction.std::string
? C'est une valeur, c'est une chaîne. Vous pouvez voir des approches similaires partout dans C ++. Cela facilite grandement l’analyse du code, tant pour les utilisateurs que pour les compilateurs.la source
Une des raisons est l'application trop large des pointeurs. Ils peuvent être utilisés pour les itérations sur les conteneurs, pour éviter de copier des objets volumineux lors du passage à une fonction, pour une gestion de la durée de vie non triviale, pour accéder à des emplacements aléatoires en mémoire, etc. immédiatement indépendamment de l'intention.
La sélection d'un outil dans le but précis rend le code plus simple et l'intention plus visible - itérateurs pour les itérations, pointeurs intelligents pour la gestion de la durée de vie, etc.
la source
Outre les raisons déjà énumérées, il en existe une évidente: de meilleures optimisations. L'analyse de repliement est beaucoup trop compliquée en présence d'un arithmétique à pointeur, alors que les références suggèrent l'optimiseur, de sorte qu'une analyse de repliement beaucoup plus profonde est possible si seules les références sont utilisées.
la source
Outre le risque de fuite de mémoire indiqué par @jmquigley, l'arithmétique de pointeur et d'arithmétique de pointeur peut être considérée comme problématique, car les pointeurs peuvent pointer partout dans la mémoire, causant des "bogues difficiles à trouver" et des "vulnérabilités en matière de sécurité".
C'est pourquoi ils ont été presque abandonnés en C # et Java.
la source
unsafe
motC ++ prend en charge la plupart des fonctions C , ainsi que des objets et des classes. C avait déjà des pointeurs et d’autres choses.
Les pointeurs sont une technique très utile, qui peut être combinée avec Orientation objet, et C ++ les prend en charge. Mais, cette technique est difficile à enseigner et à comprendre, et il est très facile de provoquer des erreurs indésirables.
Beaucoup de nouveaux langages de programmation prétendent ne pas utiliser de pointeurs avec des objets, tels que Java, .NET, Delphi, Vala, PHP, Scala. Mais, les pointeurs sont toujours utilisés, "dans les coulisses". Ces techniques de "pointeur caché" sont appelées "références".
Quoi qu'il en soit, je considère le (s) pointeur (s) comme un motif de programmation, comme un moyen valable de résoudre certains problèmes, comme le fait la programmation orientée objet .
D'autres développeurs peuvent avoir un avis différent. Mais, je suggère aux étudiants et aux programmeurs d'apprendre à:
(1) Utilisez des pointeurs sans objets
(2) objets sans pointeurs
(3) pointeurs explicites vers des objets
(4) pointeurs "cachés" vers les objets ( référence AKA ) ;-)
Dans cet ordre.
Même si c'est difficile à enseigner et difficile à apprendre. Object Pascal (Delphi, FreePascal, autres) et
C++
(pas Java ou C #) peuvent être utilisés pour ces objectifs.Et, plus tard, les programmeurs débutants peuvent utiliser des langages de programmation tels que: Java, C #, PHP orienté objet, etc.
la source
En parlant de VC6, lorsque vous transformez un pointeur d'une classe (que vous instanciez) en une variable (par exemple, DWORD), même si ce pointeur est local, vous pouvez accéder à la classe via toutes les fonctions utilisant le même segment de mémoire. La classe instanciée est définie comme locale mais en réalité, elle ne l’est pas. Autant que je sache, toute adresse de variable, structure ou classe de tas est unique tout au long de la vie de la classe d’accueil.
Exemple:
EDIT Thats une très petite partie du code original. La classe CSRecodset est uniquement une classe de transtypage de CXdbRecordset, où se trouve tout le code réel. Ce faisant, je peux laisser l’utilisateur profiter de ce que j’ai écrit sans perdre mes droits. Je ne prétends pas démontrer que mon moteur de base de données est professionnel, mais cela fonctionne vraiment.
EDIT: demandé par DeadMG:
la source
DWORD
est abusif et peut-être incorrect (DWORD n'est pas nécessairement assez large pour contenir un pointeur). Si vous avez besoin d'un pointeur non typé, utilisezvoid*
- mais lorsque vous pensez avoir besoin de cela en C ++, vous rencontrez souvent un problème de conception dans votre code que vous devez corriger.