Pourquoi devrais-je utiliser un pointeur plutôt que l'objet lui-même?
Je suis issu d'une Java d'arrière-plan et ont commencé à travailler avec des objets en C++. Mais une chose qui m'est venue est que les gens utilisent souvent des pointeurs vers des objets plutôt que les objets eux-mêmes, par exemple cette déclaration:
Object *myObject = new Object;
plutôt que:
Object myObject;
Ou au lieu d'utiliser une fonction, disons testFunc()
, comme ceci:
myObject.testFunc();
nous devons écrire:
myObject->testFunc();
Mais je ne peux pas comprendre pourquoi devrions-nous faire de cette façon. Je suppose que cela a à voir avec l'efficacité et la rapidité puisque nous obtenir un accès direct à l'adresse de la mémoire. Suis-je le droit?
- Bravo à vous pour la remise en cause de la pratique plutôt que de simplement suivre. La plupart du temps, les pointeurs sont sur-utilisés.
- Si vous ne voyez pas de raison d'utiliser des pointeurs, n'en ont pas. Préférez des objets. Préférez les objets avant de les unique_ptr avant shared_ptr avant premières des pointeurs.
- remarque: en java, tout(sauf types de base) est un pointeur. de sorte que vous devrait plutôt demander le contraire: pourquoi ai-je besoin que de simples objets?
- Notez que, en Java, les pointeurs sont cachés par la syntaxe. En C++, la différence entre un pointeur et un non-pointeur est rendu explicite dans le code. Java utilise des pointeurs partout.
- En C++11 vous avez besoin de pointeurs beaucoup moins souvent.
- Ils sont proches, mais pas identiques
- Étroite trop large? Sérieusement? Personnes, veuillez, noter que ce Java++ mode de programmation est très commun et l'un des problèmes les plus importants sur le C++ de la communauté. Il devrait être pris au sérieux.
- Plus de cinq ans après le Débordement de Pile lancé il doit y avoir un double quelque part à une telle question fondamentale .
- Liée (mais pas un doublon): C++ objets: Quand dois-je utiliser un pointeur ou une référence?
- j'ai pensé la même chose l'autre jour, mais hélas, j'ai eu tort. Peut-être vous aussi. =)
- si vous pensez que c'est trop large.. et peut-être un peu conceptuel peut-être qu'il appartient à programmers.stackexchange.com fwiw ...
- Cette question couvre beaucoup de le même territoire, mais avec une prise de conscience de moderne pointeur de gestion: Quel est l'objectif de l'étendue de pointeur?
- La chance de se refermer sur closeoverflow est directement proportionnelle à l'élégance et de l'importance de la question.
- Que pensez-vous que vous faites en Java?
- Un programmeur Java ne sait pas qu'en Java, chaque objet tapé chose est implicitement par référence?
- Protip: Utilisation make_unique (ce qui n'est pas la norme, mais bien pratiqué) ou make_shared au lieu d'utiliser le mot clé new. Nu ptrs sont mauvais. herbsutter.com/gotw/_102
- ou plutôt, Java "références" sont des pointeurs avec supprimés des opérateurs arithmétiques.
- Pourquoi devrais-je utiliser une adresse de la chambre où j'ai pu utiliser seulement la maison elle-même? Au lieu de dire à Amazon pour envoyer mon colis à 123 Nulle part Saint, je viens apporter ma maison à l'entrepôt, ils ont mis mes achats, et je le ramener.
- J'allais dire la même chose que @immibis, parce qu'un pointeur est plus léger qu'un objet
- apportez une copie de votre maison à l'entrepôt, de retour d'une autre copie et l'attribuer à votre maison et à soutenir l'industrie de la construction.
Vous devez vous connecter pour publier un commentaire.
Il est très malheureux que vous voyez à l'allocation dynamique si souvent. Cela montre juste combien de mauvais programmeurs C++ il y a des.
Dans un sens, vous avez deux questions enfermé dans une. La première, c'est quand doit-on utiliser l'allocation dynamique (à l'aide de
new
)? Le deuxième est quand devrions-nous utiliser des pointeurs?L'important à retenir est que vous devez toujours utiliser le bon outil pour le travail. Dans presque toutes les situations, il y a quelque chose de plus approprié et plus sûr que d'effectuer manuel de l'allocation dynamique et/ou utilisant des pointeurs.
Allocation dynamique
Dans votre question, vous avez fait deux façons de créer un objet. La principale différence est la durée de conservation de l'objet. Lorsque vous faites
Object myObject;
au sein d'un bloc, l'objet est créé avec automatique de la durée de stockage, ce qui signifie qu'il sera automatiquement détruite quand elle est hors de portée. Lorsque vous nenew Object()
, l'objet est dynamique, durée de stockage, ce qui signifie qu'il reste en vie jusqu'à ce que vous avez explicitementdelete
il. Vous devriez uniquement utiliser la dynamique de la durée de stockage lorsque vous en avez besoin.C'est, vous devriez toujours préfèrent la création d'objets automatique de la durée de stockage lorsque vous pouvez.
Les deux principales situations dans lesquelles vous pourriez avoir besoin d'allocation dynamique:
Lorsque vous avez absolument besoin de l'allocation dynamique, vous devez l'encapsuler dans un pointeur intelligent ou d'un autre type qui effectue RAII (comme la norme de conteneurs). Des pointeurs intelligents de fournir la propriété sémantique des objets alloués dynamiquement. Jetez un oeil à
std::unique_ptr
etstd::shared_ptr
, par exemple. Si vous les utilisez correctement, vous pouvez presque entièrement d'éviter d'effectuer votre propre gestion de la mémoire (voir la La règle de Zéro).Pointeurs
Cependant, il existe d'autres utilisations générales pour les matières premières, les pointeurs au-delà de l'allocation dynamique, mais la plupart ont des solutions de rechange que vous préférez. Comme avant, toujours préférer les alternatives à moins que vous vraiment besoin de pointeurs.
Vous avez besoin de référence sémantique. Parfois, vous voulez passer un objet à l'aide d'un pointeur (indépendamment de la façon dont il a été affecté) parce que vous voulez que la fonction à laquelle vous êtes de passage qu'il ait accès que l'objet (pas une copie). Cependant, dans la plupart des situations, vous devriez préférer les types de référence pour les pointeurs, parce que c'est précisément ce qu'ils sont conçus pour. Remarque ce n'est pas nécessairement sur l'extension de la durée de vie de l'objet au-delà de la portée actuelle, comme dans le cas 1 ci-dessus. Comme avant, si vous êtes d'accord avec le passage d'une copie de l'objet, vous n'avez pas besoin de référence sémantique.
Vous avez besoin de polymorphisme. Vous ne pouvez appeler des fonctions polymorphically (qui est, selon le type dynamique d'un objet) par l'intermédiaire d'un pointeur ou d'une référence à l'objet. Si c'est le comportement que vous avez besoin, alors vous avez besoin d'utiliser des pointeurs ou des références. De nouveau, les références devraient être privilégiées.
Vous voulez représenter qu'un objet est en option en permettant à un
nullptr
être passé quand l'objet est omis. Si c'est un argument, vous devez vous préférez utiliser des arguments par défaut ou de la fonction des surcharges. Sinon, utiliser de préférence un type qui encapsule ce comportement, tel questd::optional
(introduit en C++17 - avec les anciennes normes C++, l'utilisationboost::optional
).Vous souhaitez dissocier les unités de compilation pour améliorer le temps de compilation. La propriété intéressante d'un pointeur, c'est que vous avez seulement besoin d'une déclaration anticipée de la pointe-type (en fait d'utiliser l'objet, vous aurez besoin d'une définition). Cela vous permet de découpler les parties de votre processus de compilation, ce qui peut améliorer de façon significative le temps de compilation. Voir la Pimpl idiome.
Vous avez besoin pour l'interface avec une bibliothèque C ou un C-bibliothèque de styles. À ce stade, vous êtes obligé d'utiliser des pointeurs. La meilleure chose que vous pouvez faire est de vous assurer que vous laissez vos premières pointeurs lâche au dernier moment possible. Vous pouvez obtenir un pointeur brut à partir d'un pointeur intelligent, par exemple, à l'aide de son
get
de la fonction membre. Si une bibliothèque effectue une allocation pour vous qu'elle attend de vous libérer par l'intermédiaire d'une poignée, vous pouvez souvent envelopper la poignée vers le haut dans un pointeur intelligent avec un custom deleter, qui permettra de libérer l'objet de façon appropriée.std::vector
. Et vous avez manqué un point important 3: vous avez besoin de polymorphisme sur le type déclaré. Et bien sûr, le paragraphe qui suit, les points ne tient pas pour le point 1, ce qui est le cas le plus fréquent.const
de référence.Object myObject;
ne pouvez utiliser le constructeur par défaut, c'est à direObject();
, donc on peut utilisernew Object(param1,etc..)
pour accéder aux constructeurs surchargés, droit?Object myObject(param1, etc...)
Il y a beaucoup de cas d'utilisation pour les pointeurs.
Le comportement polymorphique. Pour les types polymorphes, les pointeurs (ou références) sont utilisés pour éviter de découpage:
De référence de la sémantique et de s'abstenir de copier. Pour les non-types polymorphes, un pointeur (ou une référence) afin d'éviter la copie potentiellement coûteux objet
Remarque que le C++11 a une sémantique de déplacement qui peut éviter de nombreuses copies d'objets coûteux en argument de fonction et les valeurs de retour. Mais à l'aide d'un pointeur sera certainement éviter de ceux et permettent à plusieurs pointeurs sur le même objet (alors qu'un objet ne peut être déplacé d'une fois).
L'acquisition de ressources. La création d'un pointeur vers une ressource à l'aide de la
new
opérateur est un anti-modèle en C++ moderne. Utiliser une ressource spéciale de la classe (l'un des conteneurs Standard) ou un pointeur intelligent (std::unique_ptr<>
oustd::shared_ptr<>
). Considérer:vs
Un pointeur brut ne devrait être utilisé qu'une "vue" et non pas en aucune façon impliqué dans la propriété, que ce soit par le biais de la création directe ou implicitement à travers les valeurs de retour. Voir aussi ce Q&A dans le C++ FAQ.
Plus précises sur la vie en temps de contrôle Chaque fois qu'un pointeur partagé est en cours de copie (par exemple, comme un argument de fonction) la ressource, il est maintenu en vie. Les objets ordinaires (non créé par
new
, soit directement par vous ou à l'intérieur d'une classe de ressource) sont détruits lorsque vous sortez de la portée.unique_ptr
/sémantique de déplacementfun(b)
ethun(b)
dans votre exemple? Je n'ai pas trouvé, mais vous l'état il est. Avez-vous besoin d'une autre variable (comme un pointeur)?hun(b)
prend une référence àb
, pas une copie. Certains guides de style (Google) l'interdit et nécessitentgun(&b)
parce quehun(b)
nécessite la connaissance de la signature de savoir si l'argument peut être modifié.hun(b)
exige également une connaissance de la signature, à moins que vous êtes bien à ne pas savoir qui vous a fourni le mauvais type jusqu'à ce que la compilation. Alors que le numéro de référence général ne pas être pris au moment de la compilation, et prendrait plus d'effort pour le debug, si vous êtes à la vérification de la signature assurez-vous que les arguments sont de droite, vous serez également en mesure de voir si les arguments sont des références de sorte que la référence bits devient quelque chose d'un non-problème (en particulier lors de l'utilisation de IDEs ou des éditeurs de texte qui montrent que la signature de certaines fonctions). Aussi,const&
.Il ya beaucoup d'excellentes réponses à cette question, y compris l'utilisation importante des cas de déclarations, polymorphisme, etc. mais j'ai le sentiment de faire partie de "l'âme" de votre question n'est pas de réponse - à savoir que les différentes syntaxes moyenne pour Java et C++.
Examinons la situation en comparant les deux langues:
Java:
L'équivalent le plus proche, est:
C++:
Nous allons voir la variante C++ façon:
La meilleure façon de penser, c'est que-plus ou moins-Java (implicitement) manipule des pointeurs vers des objets, tandis que le C++ peut traiter des pointeurs vers les objets ou les objets eux-mêmes.
Il y a des exceptions à cela, par exemple, si vous déclarez Java "primitive" types, ils sont des valeurs réelles qui sont copiés, et pas des pointeurs.
Donc,
Java:
Cela dit, en utilisant les pointeurs n'est PAS nécessairement ce soit la bonne ou la mauvaise façon de traiter les choses; toutefois, d'autres réponses ont couvert que d'une manière satisfaisante. L'idée générale est que, en C++, vous avez beaucoup plus de contrôle sur la durée de vie des objets, et l'endroit où ils vivent.
La maison, la
Object * object = new Object()
construire est en fait ce qui est le plus proche de typique Java (ou C#) à la sémantique.Object2 is now "dead"
: Je pense que tu veux diremyObject1
ou plus précisémentthe object pointed to by myObject1
.Object object1 = new Object(); Object object2 = new Object();
est très mauvais code. La deuxième nouvelle ou le deuxième constructeur de l'Objet peut jeter, et maintenant objet1 est une fuite. Si vous êtes à l'aide de matièresnew
s, vous devez enveloppernew
ed des objets dans RAII wrappers ASAP.Une autre bonne raison d'utiliser des pointeurs serait pour déclaration. Dans un assez grand projet, ils ont peut vraiment accélérer les temps de compilation.
T
. Vous avez juste besoin de faire en sorte que lorsque le destructeur de lastd::unique_ptr<T>
est appelé,T
est un type. Généralement, cela signifie que votre classe qui contient lastd::unique_ptr<T>
déclare son destructeur dans le fichier d'en-tête et la met en œuvre dans le fichier cpp (même si la mise en œuvre est vide).Préface
Java n'est rien comme C++, contrairement à l'exagération. La Java hype machine aimerais que vous croyez que, parce que Java, C++, comme la syntaxe, que les langues sont similaires. Rien ne peut être plus éloigné de la vérité. Cette désinformation est une partie de la raison pourquoi des programmeurs Java aller au C++ et à l'utilisation de Java syntaxe sans en comprendre les implications de leur code.
À partir nous allons
Le contraire, en fait. Le tas est beaucoup plus lent de la pile, parce que la pile est très simple par rapport au tas. Stockage automatique des variables (aka pile variables) ont leurs destructeurs appelé une fois qu'elles sont hors de portée. Par exemple:
D'autre part, si vous utilisez un pointeur alloué dynamiquement, son destructeur doit être appelé manuellement.
delete
appelle cette destructeur pour vous.Cela n'a rien à voir avec la
new
syntaxe répandue en C# et Java. Ils sont utilisés pour des objectifs complètement différents.Avantages de l'allocation dynamique
L'un des premiers problèmes que de nombreux programmeurs C++ est que quand ils sont accepter l'arbitraire d'entrée des utilisateurs, vous ne pouvez allouer une taille fixe pour une pile de variable. Vous ne pouvez pas modifier la taille des tableaux soit. Par exemple:
Bien sûr, si vous avez utilisé un
std::string
au lieu de cela,std::string
interne de la redimensionne, de sorte que ne devrait pas être un problème. Mais essentiellement, la solution à ce problème est l'allocation dynamique. Vous pouvez allouer de la mémoire dynamique basé sur l'entrée de l'utilisateur, par exemple:Parce que le tas est beaucoup plus grand que la pile, on peut arbitrairement allouer/réaffecter autant de mémoire qu'il/elle a besoin, alors que la pile a une limitation.
Comment est-ce un avantage, demandez-vous? La réponse sera devenu clair une fois que vous comprenez la confusion/mythe derrière les tableaux et les pointeurs. Il est communément admis que ce sont les mêmes, mais ils ne le sont pas. Ce mythe vient du fait que les pointeurs peuvent être indicée comme des tableaux et à cause de matrices de décomposition de pointeurs au plus haut niveau dans une déclaration de fonction. Cependant, une fois qu'un tableau se désintègre à un pointeur, le pointeur perd son
sizeof
de l'information. Doncsizeof(pointer)
donnera la taille du pointeur de la souris en octets, qui est généralement de 8 octets sur un système 64 bits.Vous ne pouvez pas attribuer à des tableaux, seuls les initialiser. Par exemple:
D'autre part, vous pouvez faire ce que vous voulez avec des pointeurs. Malheureusement, parce que la distinction entre les pointeurs et les tableaux sont de la main-onde, en Java et en C#, les débutants ne comprennent pas la différence.
Java et C# ont des équipements qui vous permettent de traiter les objets comme un autre, par exemple à l'aide de la
as
mot-clé. Donc, si quelqu'un voulait traiter uneEntity
objet comme unPlayer
objet, que l'on pourrait fairePlayer player = Entity as Player;
Ceci est très utile si vous avez l'intention d'appeler des fonctions en un ensemble homogène conteneur qui ne devrait s'appliquer qu'à un type spécifique. La fonctionnalité peut être réalisée d'une manière similaire ci-dessous:Donc, dire si uniquement des Triangles a une fonction de Rotation, ce serait une erreur de compilation si vous avez essayé de l'appeler sur tous les objets de la classe. À l'aide de
dynamic_cast
, vous pouvez simuler leas
mot-clé. Pour être clair, si une conversion échoue, elle renvoie un pointeur non valide. Donc!test
est essentiellement une abréviation pour vérifier sitest
est NULL ou un pointeur non valide, ce qui signifie que le cast a échoué.Avantages de variables automatiques
Après avoir vu toutes les grandes choses de l'allocation dynamique peut le faire, vous vous demandez probablement pourquoi pas à quiconque de ne PAS utiliser l'allocation dynamique de tous les temps? Je l'ai déjà dit-vous une raison, le tas est lente. Et si vous n'avez pas besoin de tout ça de mémoire, il ne faut pas en abuser. Donc, ici, sont quelques-uns des inconvénients dans aucun ordre particulier:
Elle est sujette à erreur. Manuel de l'allocation de mémoire est dangereux et vous êtes sujet à des fuites. Si vous n'êtes pas compétent dans l'utilisation du débogueur ou
valgrind
(une fuite de mémoire de l'outil), vous pouvez garder vos cheveux de votre tête. Heureusement RAII les idiomes et les pointeurs intelligents de l'alléger un peu, mais vous devez vous familiariser avec des pratiques telles que La Règle De Trois et La Règle Des Cinq. Il y a beaucoup d'informations à assimiler, et les débutants qui ne savent pas ou ne se soucient pas tomber dans ce piège.Il n'est pas nécessaire. Contrairement à Java et C#, où il est idiomatiques pour utiliser le
new
mot-clé partout, en C++, vous devez utiliser uniquement si vous en avez besoin. La commune de la phrase va, tout ressemble à un clou si vous avez un coup de marteau. Tandis que les débutants qui commencent par C++ ont peur de pointeurs et d'apprendre à utiliser des variables de pile par l'habitude, Java et C#, programmeurs démarrer en utilisant des pointeurs sans le comprendre! C'est littéralement entrer sur le mauvais pied. Vous devez abandonner tout ce que vous savez parce que la syntaxe est une chose, l'apprentissage de la langue en est une autre.Une optimisation de nombreux compilateurs faire sont des choses que l'on appelle élision et valeur de retour d'optimisation. Ces choses peuvent éviter d'inutiles copys ce qui est utile pour les objets qui sont très grandes, comme un vecteur contenant de nombreux éléments. Normalement, la pratique courante est d'utiliser des pointeurs pour transfert de propriété plutôt que de copier les grands objets de déplacer autour de lui. Ceci a conduit à la création de déplacer la sémantique et pointeurs intelligents.
Si vous êtes en utilisant des pointeurs, (N)RVO n' PAS se produire. Il est plus avantageux et moins sujettes à l'erreur de prendre avantage de (N)RVO plutôt que de retourner ou de passer des pointeurs si vous êtes inquiet au sujet de l'optimisation. Erreur des fuites peuvent se produire si l'appelant d'une fonction est responsable de l'
delete
ing un objet alloué dynamiquement, par exemple. Il peut être difficile de suivre la possession d'un objet si les pointeurs sont passés comme une patate chaude. Juste l'utilisation de la pile des variables car il est plus simple et mieux.{ std::string* s = new std::string; } delete s; // destructor called
....assurément, cedelete
ne fonctionnera pas parce que le compilateur ne sais pas ce ques
est plus?int[] nums = { 0 }; int zero = nums;
ne compile pas.C++ vous donne trois façons de passer d'un objet: par pointeur, par référence et par valeur. Java limites que vous avez avec ce dernier (la seule exception est de type primitif, comme int, boolean, etc.). Si vous souhaitez utiliser le C++ et pas seulement comme un drôle de jouet, alors vous feriez mieux d'apprendre à connaître la différence entre ces trois façons.
Java prétend qu'il n'y a pas ce problème " qui et quand doit détruire cela?". La réponse est: le Garbage Collector, Le Grand et Terrible. Néanmoins, elle ne peut pas fournir 100% de protection contre les fuites de mémoire (oui, java peut fuite de mémoire). En fait, GC vous donne un faux sentiment de sécurité. Le plus grand de votre SUV, plus votre façon de l'évacuateur.
C++ vous laisse face à face avec l'objet de la gestion du cycle de vie. Eh bien, il y a des moyens pour faire face à cette (pointeurs intelligents de la famille, de QObject en Qt et ainsi de suite), mais aucun d'eux ne peut être utilisé dans le "fire and forget", comme GC: vous devriez toujours garder à l'esprit la gestion de la mémoire. Non seulement devez-vous vous souciez de détruire un objet, vous devez également éviter de détruire l'objet même plus d'une fois.
Pas peur encore? Ok: cyclique références - gérer vous-même, de l'homme. Et n'oubliez pas: tuer chaque objet qu'une fois, précisément, nous C++ runtime n'aime pas ceux qui mess avec des cadavres, laisser les morts seuls.
Donc, pour revenir à ta question.
Lorsque vous passez votre objet par valeur, et non par pointeur ou par référence, vous copiez l'objet (l'objet entier, si c'est un couple d'octets ou une énorme base de données de vidage - vous êtes assez intelligent pour prendre soin d'éviter dernier, n'est-ce pas?) chaque fois que vous faites '='. Et pour accéder à l'objet de membres, vous utilisez '.' (dot).
Lorsque vous passez votre objet par pointeur, vous copiez juste quelques octets (4 sur les systèmes 32 bits, 8 64 bits), à savoir: - l'adresse de cet objet. Et pour montrer à tout le monde, vous utilisez cette fantaisie '->' opérateur lorsque vous accédez à la membres de. Ou vous pouvez utiliser la combinaison de '*' et '.'.
Lorsque vous utilisez des références, vous obtenez alors le pointeur qui prétend être une valeur. C'est un pointeur, mais l'accès pour les membres '.'.
Et, pour souffler votre esprit une fois de plus: lorsque vous déclarer plusieurs variables séparées par des virgules, puis une montre (les mains):
Exemple:
std::auto_ptr
est obsolète, veuillez ne pas l'utiliser.En C++, les objets alloués sur la pile (à l'aide
Object object;
instruction dans un bloc) ne vivent dans le champ d'application qu'elles sont déclarées dans. Lorsque le bloc de code à la fin de l'exécution, l'objet déclarés sont détruits.Alors que si vous allouer de la mémoire sur le tas, à l'aide de
Object* obj = new Object()
, ils continuent à vivre dans le tas jusqu'à ce que vous appelezdelete obj
.Je voudrais créer un objet sur le tas quand je veux utiliser l'objet non seulement dans le bloc de code qui déclarés/été alloué.
Object obj
n'est pas toujours sur la pile - par exemple globals ou des variables membres.Je vais comparer la façon dont il fonctionne à l'intérieur du corps de la fonction si vous utilisez:
L'intérieur de la fonction, votre
myObject
sera détruit une fois cette fonction renvoie. Si cette option est utile si vous n'avez pas besoin de votre objet à l'extérieur de votre fonction. Cet objet sera mis sur le courant de la pile des threads.Si vous écrivez à l'intérieur de corps de la fonction:
alors Objet instance de la classe pointé par
myObject
ne sera pas détruit une fois que la fonction se termine, et de l'allocation sur le tas.Maintenant, si vous êtes programmeur Java, puis le deuxième exemple est plus proche de la façon dont l'objet de l'allocation fonctionne sous java. Cette ligne:
Object *myObject = new Object;
est équivalent à java:Object myObject = new Object();
. La différence est que, en vertu de java myObject obtiendrez d'ordures collectées, alors qu'en c++ il ne sera pas libéré, vous devez quelque part explicitement appeler " supprimer monobjet;' sinon vous allez introduire des fuites de mémoire.Depuis c++11, vous pouvez utiliser des moyens sûrs d'allocations dynamiques:
new Object
, par stocker des valeurs dans shared_ptr/unique_ptr.aussi, les objets sont très souvent stockés dans des conteneurs, comme la carte-s ou vecteur-s, ils seront automatiquement gérer une durée de vie de vos objets.
then myObject will not get destroyed once function ends
Il ne peut absolument.myObject
va encore être détruits, de même que toute autre variable locale sera. La différence, c'est que sa valeur est un pointeur pour un objet, et non l'objet lui-même, et d'un muet du pointeur de la destruction n'affecte pas ses pointee. Si le objet va survivre à ladite destruction.Techniquement, c'est un problème d'allocation de mémoire, cependant, ici, sont deux aspects plus pratiques de la ce.
Il a à faire à deux choses:
1) Champ d'application, lorsque vous définissez un objet sans pointeur, vous ne pourrez plus accéder après le bloc de code il est défini, alors que si vous définissez un pointeur avec les "nouvelles", alors vous pouvez y accéder à partir de n'importe où vous avez un pointeur vers cette mémoire jusqu'à ce que vous appelez "supprimer" sur le même pointeur.
2) Si vous voulez passer des arguments à une fonction que vous souhaitez passer un pointeur ou une référence dans le but d'être plus efficace. Lorsque vous transmettez un Objet puis l'objet est copié, si c'est un objet qui utilise beaucoup de mémoire ce pourrait être la consommation PROCESSEUR (par exemple, la copie d'un vecteur plein de données). Lorsque vous passez un pointeur tous les vous pass est un int (en fonction de la mise en œuvre, mais la plupart d'entre eux sont un int).
Autres que ce que vous avez besoin de comprendre que la "nouvelle" alloue de la mémoire sur le tas qui doit être libéré à un certain point. Lorsque vous n'avez pas à utiliser "nouveaux", je vous suggère d'utiliser un objet définition de "sur la pile".
Bien la question principale est de Pourquoi devrais-je utiliser un pointeur plutôt que l'objet lui-même? Et ma réponse, vous devez (ou presque) ne jamais utiliser de pointeur à la place de l'objet, parce que le C++ a références, il est plus sûr alors pointeurs et garantit le même niveau de performance que les pointeurs.
Une autre chose que vous avez mentionné dans votre question:
Comment ça fonctionne? Il crée pointeur de
Object
type, alloue de la mémoire pour s'adapter à un objet et les appels de constructeur par défaut, ça sonne bien, non? Mais en fait il n'est pas si bon, si vous avez la mémoire allouée dynamiquement (mot-clé utilisénew
), vous avez également de libérer de la mémoire manuellement, cela signifie que dans le code, vous devez avoir:Ce appels destructeur et libère de la mémoire, semble facile, mais dans les gros projets peut être difficile à détecter si un thread de mémoire libérée ou pas, mais pour cela vous pouvez essayer partagé pointeurs, ces diminue légèrement les performances, mais il est beaucoup plus facile de travailler avec eux.
Et maintenant, une partie de l'introduction est en cours et revenir à la question.
Vous pouvez utiliser des pointeurs au lieu d'objets pour obtenir de meilleures performances lors du transfert de données entre la fonction.
Prendre un coup d'oeil, vous avez
std::string
(c'est d'ailleurs l'objet) et il contient beaucoup de données, par exemple big XML, maintenant, vous devez l'analyser, mais pour cela vous avez la fonctionvoid foo(...)
qui peut être declarated de différentes façons:void foo(std::string xml);
Dans ce cas, vous pouvez copier toutes les données de votre variable en fonction de la pile, il faut un certain temps, de sorte que votre rendement sera faible.
void foo(std::string* xml);
Dans ce cas, vous passerez pointeur vers l'objet, même vitesse que le passage
size_t
variable, cependant, cette déclaration a enclins à faire des erreurs, parce que vous pouvez passerNULL
pointeur ou un pointeur invalide. Les pointeurs généralement utilisé dansC
car il n'a pas de références.void foo(std::string& xml);
Ici, vous passez de référence, en gros, c'est le même que le passage du pointeur, mais le compilateur n'quelques trucs et vous ne pouvez pas passer à référence non valide (en fait, il est possible de créer de situation de référence non valide, mais il est de tromper le compilateur).
void foo(const std::string* xml);
Ici est la même que la deuxième, la valeur du pointeur ne peut pas être modifié.
void foo(const std::string& xml);
Ici est le même que le troisième, mais la valeur de l'objet ne peut pas être modifié.
Plus ce que je veux mentionner, vous pouvez utiliser ces 5 façons de transmettre les données de n'importe qui d'allocation chemin que vous avez choisi (avec
new
ou régulière).Une autre chose à mentionner, lorsque vous créez un objet dans régulière façon, allouer de la mémoire dans la pile, mais pendant que vous créez avec
new
vous allouer du tas. Il est beaucoup plus rapide d'allouer de la pile, mais il est un peu petit pour vraiment de grands tableaux de données, donc si vous avez besoin d'un grand objet vous devez utiliser des tas, parce que vous pouvez obtenir de débordement de pile, mais généralement, ce problème est résolu en utilisant Des conteneurs STL et n'oubliez passtd::string
est aussi conteneur, certains gars oublié 🙂Disons que vous avez
class A
qui contiennentclass B
Lorsque vous souhaitez appeler une fonction declass B
à l'extérieurclass A
vous simplement obtenir un pointeur vers cette classe et vous pouvez faire ce que vous voulez et il sera également modifier le contexte declass B
dans votreclass A
Mais être prudent avec les objets dynamiques
Il ya de nombreux avantages de l'utilisation de pointeurs d'objet -
fonctions de création de nouvelles copies de l'objet.
appartient à un tiers de code et les auteurs ont l'intention de l'utilisation de leurs objets par le biais de pointeurs (pas de copie des constructeurs etc) la seule façon vous pouvez passer autour de ce
l'objet est l'aide de pointeurs. Passage par valeur peut causer des problèmes. (Profonde
copie /copie superficielle des questions).
Ce qui a été discuté lors de la longueur, mais en Java tout est un pointeur. Il ne fait pas de distinction entre la pile et le tas allocations (tous les objets sont alloués sur le tas), de sorte que vous ne réalisez pas que vous êtes en utilisant les pointeurs. En C++, vous pouvez mélanger les deux, en fonction de vos exigences de mémoire. Les performances et l'utilisation de la mémoire est plus déterministe en C++ (duh).
Ceci vous permettra de créer une référence à un Objet (sur le tas), qui doit être supprimé explicitement pour éviter fuite de mémoire.
Ceci vous permettra de créer un objet(monobjet) de la automatique type (sur la pile) qui seront automatiquement supprimés lorsque l'objet(monobjet) est hors de portée.
Un pointeur directement référence à l'emplacement de la mémoire d'un objet. Java n'a rien de ce genre. Java a des références qui font référence à la localisation de l'objet par le biais de tables de hachage. Vous ne pouvez rien faire, comme l'arithmétique des pointeurs en Java avec ces références.
Pour répondre à votre question, c'est juste votre préférence. Je préfère utiliser le Java syntaxe.
MyClass[]
pour émuler le pointeur de mathématiquesAvec des pointeurs ,
pouvez parler directement à la mémoire.
peut empêcher beaucoup de fuites de mémoire de programme en manipulant des pointeurs.
L'une des raisons pour l'utilisation des pointeurs est à l'interface avec les fonctions C. Une autre raison est d'économiser de la mémoire; par exemple: au lieu de passer d'un objet qui contient beaucoup de données et d'un processeur constructeur par copie d'une fonction, il suffit de passer un pointeur vers l'objet, d'économiser la mémoire et de la vitesse, surtout si vous êtes dans une boucle, mais une référence serait mieux dans ce cas, sauf si vous utilisez un C-gamme de style.
Dans les zones où l'utilisation de la mémoire est à sa prime , les pointeurs, vient à portée de main. Par exemple, considérons un algorithme minimax, où des milliers de nœuds seront générés à l'aide de routine récursive, et, plus tard, les utiliser pour évaluer la meilleure déplacer dans le jeu, la capacité de libérer ou de réinitialisation (comme dans les smart pointers) réduit considérablement la consommation de mémoire. Alors que le non-pointeur de variable continue à occuper l'espace jusqu'à ce qu'il est récursif appel renvoie une valeur.
Je vais inclure un important cas d'utilisation de pointeur. Lorsque vous stockez un objet de la classe de base, mais il pourrait être polymorphe.
Dans ce cas, vous ne pouvez pas déclarer bObj comme un objet direct, vous devez avoir pointeur.
"La nécessité est mère de l'invention".
La plupart de la différence importante que je voudrais souligner est que le résultat de ma propre expérience de codage.
Parfois, vous avez besoin pour passer des objets à des fonctions. Dans ce cas, si votre objet est d'une très grande classe, puis de le transmettre comme un objet copie de son état (ce que vous ne voulez ..ET PEUT ÊTRE d'un GRAND frais GÉNÉRAUX) résultant d'une surcharge de copie de l'objet .alors que le pointeur est fixé à 4 octets taille (en supposant 32 bits). D'autres raisons sont déjà mentionné ci-dessus...
std::string test;
nous avonsvoid func(const std::string &) {}
mais à moins que la fonction a besoin de modifier les entrées dans ce cas, je vous recommandons d'utiliser des pointeurs (de sorte que tous ceux qui lisent le code ne avis&
, et il comprend la fonction peut modifier son entrée)Il existe de nombreuses excellentes réponses déjà, mais laissez-moi vous donner un exemple:
J'ai un Élément simple classe:
- Je faire un vecteur de tenir un tas d'entre eux.
std::vector<Item> inventory;
J'ai créer un million d'objets d'éléments, et de le repousser sur le vecteur. Je trie le vecteur par nom, puis faire un simple itératif de recherche binaire pour un particulier du nom de l'élément. J'ai tester le programme, et il faut plus de 8 minutes pour terminer l'exécution. Puis-je changer mon inventaire vecteur de la sorte:
std::vector<Item *> inventory;
...et de créer mon millions d'objets d'éléments par le biais des nouvelles. Les SEULES modifications que je fais sur mon code pour utiliser les pointeurs à des Éléments, à l'exception d'une boucle-je ajouter de la mémoire de nettoyage à la fin. Ce programme s'exécute en moins de 40 secondes, ou mieux qu'un 10x augmentation de la vitesse.
EDIT: Le code est à http://pastebin.com/DK24SPeW
Avec les optimisations du compilateur, il montre seulement 3,4 x augmentation sur la machine, je l'ai juste testé sur, ce qui est encore considérable.
push_back
. Bien sûr, cela copies. Vous devez avoir étéemplace
ing en place lors de la création de vos objets (sauf si vous en avez besoin pour être mis en cache d'ailleurs).