J'ai lu dans quelques articles que les pointeurs bruts ne devraient presque jamais être utilisés. Au lieu de cela, ils doivent toujours être enveloppés dans des pointeurs intelligents, qu'il s'agisse de pointeurs étendus ou partagés.
Cependant, j'ai remarqué que les frameworks comme Qt, wxWidgets et les bibliothèques comme Boost ne reviennent jamais et n'attendent jamais de pointeurs intelligents, comme s'ils ne les utilisaient pas du tout. Au lieu de cela, ils retournent ou s'attendent à des pointeurs bruts. Y a-t-il une raison à cela? Dois-je rester à l'écart des pointeurs intelligents lorsque j'écris une API publique, et pourquoi?
Je me demande simplement pourquoi les pointeurs intelligents sont recommandés alors que de nombreux projets majeurs semblent les éviter.
la source
unique_ptr
? Pas du tout. Les Qt / WxWidgets sont-ils ciblés sur des systèmes embarqués ou en temps réel? Non, ils sont destinés à Windows / Mac / Unix sur un bureau au maximum. Les pointeurs intelligents sont destinés aux programmeurs qui souhaitent le corriger.Réponses:
Outre le fait que de nombreuses bibliothèques ont été écrites avant l'avènement des pointeurs intelligents standard, la principale raison est probablement l'absence d'une interface binaire d'application (ABI) C ++ standard.
Si vous écrivez une bibliothèque d'en-tête uniquement, vous pouvez transmettre des pointeurs intelligents et des conteneurs standard à votre guise. Leur source est disponible pour votre bibliothèque au moment de la compilation, vous comptez donc uniquement sur la stabilité de leurs interfaces, et non sur leurs implémentations.
Mais en raison de l'absence d'ABI standard, vous ne pouvez généralement pas passer ces objets en toute sécurité à travers les limites du module. Un GCC
shared_ptr
est probablement différent d'un MSVCshared_ptr
, qui peut également différer d'un Intelshared_ptr
. Même avec le même compilateur, ces classes ne sont pas garanties d'être compatibles binaires entre les versions.L'essentiel est que si vous souhaitez distribuer une version prédéfinie de votre bibliothèque, vous avez besoin d'une ABI standard sur laquelle vous appuyer. C n'en a pas, mais les fournisseurs de compilateurs sont très bons en matière d'interopérabilité entre les bibliothèques C pour une plate-forme donnée - il existe des normes de facto.
La situation n'est pas aussi bonne pour C ++. Les compilateurs individuels peuvent gérer l'interopérabilité entre leurs propres binaires, vous avez donc la possibilité de distribuer une version pour chaque compilateur pris en charge, souvent GCC et MSVC. Mais à la lumière de cela, la plupart des bibliothèques exportent simplement une interface C - et cela signifie des pointeurs bruts.
Cependant, le code non-bibliothèque devrait généralement préférer les pointeurs intelligents au brut.
la source
Il peut y avoir plusieurs raisons. Pour en citer quelques-uns:
Edit : L'utilisation de pointeurs intelligents est entièrement le choix du développeur. Cela dépend de divers facteurs.
Dans les systèmes à performances critiques, vous ne souhaiterez peut-être pas utiliser de pointeurs intelligents qui génèrent une surcharge
Le projet qui a besoin de la compatibilité descendante, vous ne voudrez peut-être pas utiliser les pointeurs intelligents qui ont des fonctionnalités spécifiques à C ++ 11
Edit2 Il y a une série de plusieurs votes négatifs en l'espace de 24 heures en raison du passage ci-dessous. Je ne comprends pas pourquoi la réponse est rejetée même si ci-dessous n'est qu'une suggestion complémentaire et non une réponse.
Cependant, C ++ vous facilite toujours l'ouverture des options. :) par exemple
Et dans votre code, utilisez-le comme:
Pour ceux qui disent qu'un pointeur intelligent et un pointeur brut sont différents, je suis d'accord avec cela. Le code ci-dessus était juste une idée où l'on peut écrire un code qui est interchangeable juste avec un
#define
, ce n'est pas une contrainte ;Par exemple,
T*
doit être supprimé explicitement, mais pas un pointeur intelligent. Nous pouvons avoir un modèleDestroy()
pour gérer cela.et utilisez-le comme:
De la même manière, pour un pointeur brut, nous pouvons le copier directement et pour un pointeur intelligent, nous pouvons utiliser une opération spéciale.
Où
Assign()
est comme:la source
std::auto_ptr
cela fait partie de la norme depuis longtemps (et notez que j'aimestd::auto_ptr
comme type de retour pour les fonctions créant des objets, même si c'est presque inutile partout ailleurs). En C ++ 11std::unique_ptr
n'a pas de coûts supplémentaires par rapport à un simple pointeur.unique_ptr
et la disparition deauto_ptr
, le code ciblant C ++ 03 devrait utiliser le plus tard, tandis que le code ciblant C ++ 11 peut utiliser l'ancien. Les pointeurs intelligents ne le sont passhared_ptr
, il existe de nombreuses normes et aucune norme, y compris des propositions à la norme qui ont été rejetées commemanaged_ptr
unique_ptr
coût d'exécution,unique_ptr
sont de loin celui qui est le plus couramment utilisé. L'exemple de code que vous fournissez est également trompeur, carunique_ptr
et ceT*
sont des concepts entièrement différents. Le fait que vous vous référiez aux deux commetype
donne l'impression qu'ils peuvent être échangés l'un contre l'autre.Il y a deux problèmes avec les pointeurs intelligents (pré C ++ 11):
Le pointeur intelligent par défaut , en ce qu'il est gratuit, est
unique_ptr
. Malheureusement, il nécessite une sémantique de déplacement C ++ 11, qui n'est apparue que récemment. Tous les autres pointeurs intelligents ont un coût (shared_ptr
,intrusive_ptr
) ou ont une sémantique moins qu'idéale (auto_ptr
).Avec C ++ 11 au coin de la rue, apportant un
std::unique_ptr
, on serait tenté de penser que c'est enfin fini ... Je ne suis pas si optimiste.Seuls quelques grands compilateurs implémentent la plupart de C ++ 11, et uniquement dans leurs versions récentes. Nous pouvons nous attendre à ce que les grandes bibliothèques telles que QT et Boost soient disposées à conserver la compatibilité avec C ++ 03 pendant un certain temps, ce qui empêche quelque peu l'adoption à grande échelle des nouveaux et brillants pointeurs intelligents.
la source
Vous ne devriez pas rester à l'écart des pointeurs intelligents, ils ont leur utilité en particulier dans les applications où vous devez passer un objet.
Les bibliothèques ont tendance à renvoyer simplement une valeur ou à remplir un objet. Ils n'ont généralement pas d'objets qui doivent être utilisés dans de nombreux endroits, il n'est donc pas nécessaire qu'ils utilisent des pointeurs intelligents (du moins pas dans leur interface, ils peuvent les utiliser en interne).
Je pourrais prendre comme exemple une bibliothèque sur laquelle nous avons travaillé, où, après quelques mois de développement, j'ai réalisé que nous n'utilisions que des pointeurs et des pointeurs intelligents dans quelques classes (3-5% de toutes les classes).
Passer des variables par référence était suffisant dans la plupart des endroits, nous utilisions des pointeurs intelligents chaque fois que nous avions un objet qui pouvait être nul, et des pointeurs bruts lorsqu'une bibliothèque que nous utilisions nous y obligeait.
Edit (je ne peux pas commenter à cause de ma réputation): passer des variables par référence est très flexible: si vous voulez que l'objet soit en lecture seule, vous pouvez utiliser une référence const (vous pouvez quand même faire de vilains casts pour pouvoir écrire l'objet ) mais vous obtenez le maximum de protection possible (c'est la même chose avec les pointeurs intelligents). Mais je suis d'accord qu'il est beaucoup plus agréable de simplement renvoyer l'objet.
la source
Qt a inutilement réinventé de nombreuses parties de la bibliothèque Standard pour tenter de devenir Java. Je pense qu'il a en fait ses propres pointeurs intelligents maintenant, mais en général, ce n'est pas le summum du design. wxWidgets, pour autant que je sache, a été conçu bien avant l'écriture des pointeurs intelligents utilisables.
Quant à Boost, je m'attends à ce qu'ils utilisent des pointeurs intelligents le cas échéant. Vous devrez peut-être être plus précis.
De plus, n'oubliez pas que des pointeurs intelligents existent pour renforcer la propriété. Si l'API n'a pas de sémantique de propriété, alors pourquoi utiliser un pointeur intelligent?
la source
QString
, wxWidgets awxString
, MFC a horriblement nomméCString
. Un UTF-8 n'est-il passtd::string
assez bon pour 99% des tâches de l'interface graphique?Bonne question. Je ne connais pas les articles spécifiques auxquels vous faites référence, mais j'ai lu des choses similaires de temps en temps. Je soupçonne que les auteurs de tels articles ont tendance à entretenir un parti pris contre la programmation de style C ++. Si l'écrivain programme en C ++ seulement quand il le doit, puis retourne à Java ou tel dès qu'il le peut, alors il ne partage pas vraiment l'état d'esprit C ++.
On soupçonne que certains ou la plupart des mêmes écrivains préfèrent les gestionnaires de mémoire de récupération de place. Je ne le fais pas, mais je pense différemment d'eux.
Les pointeurs intelligents sont excellents, mais ils doivent garder le nombre de références. La tenue des comptages de référence entraîne des coûts - souvent modestes, mais néanmoins des coûts - au moment de l'exécution. Il n'y a rien de mal à économiser ces coûts en utilisant des pointeurs nus, surtout si les pointeurs sont gérés par des destructeurs.
L'un des excellents avantages du C ++ est sa prise en charge de la programmation des systèmes embarqués. L'utilisation de pointeurs nus en fait partie.
Mise à jour: Un commentateur a correctement observé que le nouveau C ++
unique_ptr
(disponible depuis TR1) ne compte pas les références. Le commentateur a également une définition de «pointeur intelligent» différente de celle que j'ai à l'esprit. Il a peut-être raison sur la définition.Mise à jour supplémentaire: le fil de commentaires ci-dessous est éclairant. Tout cela est une lecture recommandée.
la source
shared_ptr
conserve un décompte de références. Il existe de nombreux autres types de pointeurs intelligents qui ne conservent pas du tout un nombre de références. Enfin, les bibliothèques mentionnées sont destinées aux plates-formes qui ont beaucoup de ressources à revendre. Ce n’est pas que j’ai été le contrevenant, mais tout ce que je dis, c’est que votre message est plein de faux.shared_ptr
n'a pas de frais généraux. Il n'a de surcharge que si vous n'avez pas besoin de sémantique de propriété partagée thread-safe, ce qu'il fournit.Il existe également d'autres types de pointeurs intelligents. Vous voudrez peut-être un pointeur intelligent spécialisé pour quelque chose comme la réplication réseau (un qui détecte s'il y a accès et envoie des modifications au serveur ou quelque chose du genre), conserve un historique des modifications, marque le fait qu'il a été accédé afin qu'il puisse être étudié lorsque vous enregistrez des données sur le disque et ainsi de suite. Je ne sais pas si faire cela dans le pointeur est la meilleure solution, mais l'utilisation des types de pointeurs intelligents intégrés dans les bibliothèques pourrait entraîner le verrouillage des personnes et perdre la flexibilité.
Les gens peuvent avoir toutes sortes d'exigences et de solutions de gestion de la mémoire différentes au-delà des pointeurs intelligents. Je pourrais vouloir gérer la mémoire moi-même, je pourrais allouer de l'espace pour des choses dans un pool de mémoire afin qu'il soit alloué à l'avance et non au moment de l'exécution (utile pour les jeux). J'utilise peut-être une implémentation garbage collector de C ++ (C ++ 11 rend cela possible bien qu'il n'en existe pas encore). Ou peut-être que je ne fais rien d'assez avancé pour me soucier de m'embêter avec eux, je peux savoir que je n'oublierai pas les objets non initialisés et ainsi de suite. Peut-être que je suis juste confiant dans ma capacité à gérer la mémoire sans la béquille du pointeur.
L'intégration avec C est également un autre problème.
Un autre problème est que les pointeurs intelligents font partie de la STL. C ++ est conçu pour être utilisable sans la STL.
la source
Cela dépend aussi du domaine dans lequel vous travaillez. J'écris des moteurs de jeu pour gagner ma vie, nous évitons les boosters comme la peste, dans les jeux, la surcharge de boost n'est pas acceptable. Dans notre moteur principal, nous avons fini par écrire notre propre version de stl (un peu comme ea stl).
Si je devais rédiger une application de formulaires, je pourrais envisager d'utiliser des pointeurs intelligents; mais une fois que la gestion de la mémoire est une seconde nature, ne pas avoir de contrôle granulaire sur la mémoire devient assez ennuyeux.
la source